OLD | NEW |
| (Empty) |
1 // Copyright (c) 2011 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_ctrl_response_buffer.h" | |
6 | |
7 #include "base/bind.h" | |
8 #include "base/logging.h" | |
9 #include "base/strings/string_number_conversions.h" | |
10 #include "base/strings/string_piece.h" | |
11 #include "base/values.h" | |
12 #include "net/base/net_errors.h" | |
13 | |
14 namespace net { | |
15 | |
16 // static | |
17 const int FtpCtrlResponse::kInvalidStatusCode = -1; | |
18 | |
19 FtpCtrlResponse::FtpCtrlResponse() : status_code(kInvalidStatusCode) {} | |
20 | |
21 FtpCtrlResponse::~FtpCtrlResponse() {} | |
22 | |
23 FtpCtrlResponseBuffer::FtpCtrlResponseBuffer(const BoundNetLog& net_log) | |
24 : multiline_(false), | |
25 net_log_(net_log) { | |
26 } | |
27 | |
28 FtpCtrlResponseBuffer::~FtpCtrlResponseBuffer() {} | |
29 | |
30 int FtpCtrlResponseBuffer::ConsumeData(const char* data, int data_length) { | |
31 buffer_.append(data, data_length); | |
32 ExtractFullLinesFromBuffer(); | |
33 | |
34 while (!lines_.empty()) { | |
35 ParsedLine line = lines_.front(); | |
36 lines_.pop(); | |
37 | |
38 if (multiline_) { | |
39 if (!line.is_complete || line.status_code != response_buf_.status_code) { | |
40 line_buf_.append(line.raw_text); | |
41 continue; | |
42 } | |
43 | |
44 response_buf_.lines.push_back(line_buf_); | |
45 | |
46 line_buf_ = line.status_text; | |
47 DCHECK_EQ(line.status_code, response_buf_.status_code); | |
48 | |
49 if (!line.is_multiline) { | |
50 response_buf_.lines.push_back(line_buf_); | |
51 responses_.push(response_buf_); | |
52 | |
53 // Prepare to handle following lines. | |
54 response_buf_ = FtpCtrlResponse(); | |
55 line_buf_.clear(); | |
56 multiline_ = false; | |
57 } | |
58 } else { | |
59 if (!line.is_complete) | |
60 return ERR_INVALID_RESPONSE; | |
61 | |
62 response_buf_.status_code = line.status_code; | |
63 if (line.is_multiline) { | |
64 line_buf_ = line.status_text; | |
65 multiline_ = true; | |
66 } else { | |
67 response_buf_.lines.push_back(line.status_text); | |
68 responses_.push(response_buf_); | |
69 | |
70 // Prepare to handle following lines. | |
71 response_buf_ = FtpCtrlResponse(); | |
72 line_buf_.clear(); | |
73 } | |
74 } | |
75 } | |
76 | |
77 return OK; | |
78 } | |
79 | |
80 namespace { | |
81 | |
82 base::Value* NetLogFtpCtrlResponseCallback(const FtpCtrlResponse* response, | |
83 NetLog::LogLevel log_level) { | |
84 base::ListValue* lines = new base::ListValue(); | |
85 lines->AppendStrings(response->lines); | |
86 | |
87 base::DictionaryValue* dict = new base::DictionaryValue(); | |
88 dict->SetInteger("status_code", response->status_code); | |
89 dict->Set("lines", lines); | |
90 return dict; | |
91 } | |
92 | |
93 } // namespace | |
94 | |
95 FtpCtrlResponse FtpCtrlResponseBuffer::PopResponse() { | |
96 FtpCtrlResponse result = responses_.front(); | |
97 responses_.pop(); | |
98 | |
99 net_log_.AddEvent(NetLog::TYPE_FTP_CONTROL_RESPONSE, | |
100 base::Bind(&NetLogFtpCtrlResponseCallback, &result)); | |
101 | |
102 return result; | |
103 } | |
104 | |
105 FtpCtrlResponseBuffer::ParsedLine::ParsedLine() | |
106 : has_status_code(false), | |
107 is_multiline(false), | |
108 is_complete(false), | |
109 status_code(FtpCtrlResponse::kInvalidStatusCode) { | |
110 } | |
111 | |
112 // static | |
113 FtpCtrlResponseBuffer::ParsedLine FtpCtrlResponseBuffer::ParseLine( | |
114 const std::string& line) { | |
115 ParsedLine result; | |
116 | |
117 if (line.length() >= 3) { | |
118 if (base::StringToInt(base::StringPiece(line.begin(), line.begin() + 3), | |
119 &result.status_code)) | |
120 result.has_status_code = (100 <= result.status_code && | |
121 result.status_code <= 599); | |
122 if (result.has_status_code && line.length() >= 4 && line[3] == ' ') { | |
123 result.is_complete = true; | |
124 } else if (result.has_status_code && line.length() >= 4 && line[3] == '-') { | |
125 result.is_complete = true; | |
126 result.is_multiline = true; | |
127 } | |
128 } | |
129 | |
130 if (result.is_complete) { | |
131 result.status_text = line.substr(4); | |
132 } else { | |
133 result.status_text = line; | |
134 } | |
135 | |
136 result.raw_text = line; | |
137 | |
138 return result; | |
139 } | |
140 | |
141 void FtpCtrlResponseBuffer::ExtractFullLinesFromBuffer() { | |
142 int cut_pos = 0; | |
143 for (size_t i = 0; i < buffer_.length(); i++) { | |
144 if (i >= 1 && buffer_[i - 1] == '\r' && buffer_[i] == '\n') { | |
145 lines_.push(ParseLine(buffer_.substr(cut_pos, i - cut_pos - 1))); | |
146 cut_pos = i + 1; | |
147 } | |
148 } | |
149 buffer_.erase(0, cut_pos); | |
150 } | |
151 | |
152 } // namespace net | |
OLD | NEW |