Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(79)

Side by Side Diff: net/ftp/ftp_directory_listing_buffer.cc

Issue 6670085: FTP: Detect the character encoding only after the entire listing is received. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: test coverage Created 9 years, 9 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
« no previous file with comments | « net/ftp/ftp_directory_listing_buffer.h ('k') | net/ftp/ftp_directory_listing_parser.h » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
(Empty)
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
3 // found in the LICENSE file.
4
5 #include "net/ftp/ftp_directory_listing_buffer.h"
6
7 #include "base/i18n/icu_encoding_detection.h"
8 #include "base/i18n/icu_string_conversions.h"
9 #include "base/stl_util-inl.h"
10 #include "base/string_util.h"
11 #include "net/base/net_errors.h"
12 #include "net/ftp/ftp_directory_listing_parser_ls.h"
13 #include "net/ftp/ftp_directory_listing_parser_netware.h"
14 #include "net/ftp/ftp_directory_listing_parser_vms.h"
15 #include "net/ftp/ftp_directory_listing_parser_windows.h"
16
17 namespace net {
18
19 FtpDirectoryListingBuffer::FtpDirectoryListingBuffer(
20 const base::Time& current_time)
21 : current_parser_(NULL) {
22 parsers_.insert(new FtpDirectoryListingParserLs(current_time));
23 parsers_.insert(new FtpDirectoryListingParserNetware(current_time));
24 parsers_.insert(new FtpDirectoryListingParserVms());
25 parsers_.insert(new FtpDirectoryListingParserWindows());
26 }
27
28 FtpDirectoryListingBuffer::~FtpDirectoryListingBuffer() {
29 STLDeleteElements(&parsers_);
30 }
31
32 int FtpDirectoryListingBuffer::ConsumeData(const char* data, int data_length) {
33 buffer_.append(data, data_length);
34
35 if (!encoding_.empty() || buffer_.length() > 1024) {
36 int rv = ConsumeBuffer();
37 if (rv != OK)
38 return rv;
39 }
40
41 return ParseLines();
42 }
43
44 int FtpDirectoryListingBuffer::ProcessRemainingData() {
45 int rv = ConsumeBuffer();
46 if (rv != OK)
47 return rv;
48
49 DCHECK(buffer_.empty());
50 if (!converted_buffer_.empty())
51 return ERR_INVALID_RESPONSE;
52
53 rv = ParseLines();
54 if (rv != OK)
55 return rv;
56
57 rv = OnEndOfInput();
58 if (rv != OK)
59 return rv;
60
61 return OK;
62 }
63
64 bool FtpDirectoryListingBuffer::EntryAvailable() const {
65 return (current_parser_ ? current_parser_->EntryAvailable() : false);
66 }
67
68 FtpDirectoryListingEntry FtpDirectoryListingBuffer::PopEntry() {
69 DCHECK(EntryAvailable());
70 return current_parser_->PopEntry();
71 }
72
73 FtpServerType FtpDirectoryListingBuffer::GetServerType() const {
74 return (current_parser_ ? current_parser_->GetServerType() : SERVER_UNKNOWN);
75 }
76
77 int FtpDirectoryListingBuffer::DecodeBufferUsingEncoding(
78 const std::string& encoding) {
79 string16 converted;
80 if (!base::CodepageToUTF16(buffer_,
81 encoding.c_str(),
82 base::OnStringConversionError::FAIL,
83 &converted))
84 return ERR_ENCODING_CONVERSION_FAILED;
85
86 buffer_.clear();
87 converted_buffer_ += converted;
88 return OK;
89 }
90
91 int FtpDirectoryListingBuffer::ConvertBufferToUTF16() {
92 if (encoding_.empty()) {
93 std::vector<std::string> encodings;
94 if (!base::DetectAllEncodings(buffer_, &encodings))
95 return ERR_ENCODING_DETECTION_FAILED;
96
97 // Use first encoding that can be used to decode the buffer.
98 for (size_t i = 0; i < encodings.size(); i++) {
99 if (DecodeBufferUsingEncoding(encodings[i]) == OK) {
100 encoding_ = encodings[i];
101 return OK;
102 }
103 }
104
105 return ERR_ENCODING_DETECTION_FAILED;
106 }
107
108 return DecodeBufferUsingEncoding(encoding_);
109 }
110
111 void FtpDirectoryListingBuffer::ExtractFullLinesFromBuffer() {
112 int cut_pos = 0;
113 // TODO(phajdan.jr): This code accepts all endlines matching \r*\n. Should it
114 // be more strict, or enforce consistent line endings?
115 for (size_t i = 0; i < converted_buffer_.length(); ++i) {
116 if (converted_buffer_[i] != '\n')
117 continue;
118 int line_length = i - cut_pos;
119 if (i >= 1 && converted_buffer_[i - 1] == '\r')
120 line_length--;
121 lines_.push_back(converted_buffer_.substr(cut_pos, line_length));
122 cut_pos = i + 1;
123 }
124 converted_buffer_.erase(0, cut_pos);
125 }
126
127 int FtpDirectoryListingBuffer::ConsumeBuffer() {
128 int rv = ConvertBufferToUTF16();
129 if (rv != OK)
130 return rv;
131
132 ExtractFullLinesFromBuffer();
133 return OK;
134 }
135
136 int FtpDirectoryListingBuffer::ParseLines() {
137 while (!lines_.empty()) {
138 string16 line = lines_.front();
139 lines_.pop_front();
140 if (current_parser_) {
141 if (!current_parser_->ConsumeLine(line))
142 return ERR_FAILED;
143 } else {
144 ParserSet::iterator i = parsers_.begin();
145 while (i != parsers_.end()) {
146 if ((*i)->ConsumeLine(line)) {
147 i++;
148 } else {
149 delete *i;
150 parsers_.erase(i++);
151 }
152 }
153 if (parsers_.empty())
154 return ERR_UNRECOGNIZED_FTP_DIRECTORY_LISTING_FORMAT;
155 if (parsers_.size() == 1)
156 current_parser_ = *parsers_.begin();
157 }
158 }
159
160 return OK;
161 }
162
163 int FtpDirectoryListingBuffer::OnEndOfInput() {
164 ParserSet::iterator i = parsers_.begin();
165 while (i != parsers_.end()) {
166 if ((*i)->OnEndOfInput()) {
167 i++;
168 } else {
169 delete *i;
170 parsers_.erase(i++);
171 }
172 }
173
174 if (parsers_.size() != 1) {
175 current_parser_ = NULL;
176
177 // We may hit an ambiguity in case of listings which have no entries. That's
178 // fine, as long as all remaining parsers agree that the listing is empty.
179 bool all_listings_empty = true;
180 for (ParserSet::iterator i = parsers_.begin(); i != parsers_.end(); ++i) {
181 if ((*i)->EntryAvailable())
182 all_listings_empty = false;
183 }
184 if (all_listings_empty)
185 return OK;
186
187 return ERR_UNRECOGNIZED_FTP_DIRECTORY_LISTING_FORMAT;
188 }
189
190 current_parser_ = *parsers_.begin();
191 return OK;
192 }
193
194 } // namespace net
OLDNEW
« no previous file with comments | « net/ftp/ftp_directory_listing_buffer.h ('k') | net/ftp/ftp_directory_listing_parser.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698