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.
5 #include "net/ftp/ftp_ctrl_response_buffer.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"
17 const int FtpCtrlResponse::kInvalidStatusCode
= -1;
19 FtpCtrlResponse::FtpCtrlResponse() : status_code(kInvalidStatusCode
) {}
21 FtpCtrlResponse::~FtpCtrlResponse() {}
23 FtpCtrlResponseBuffer::FtpCtrlResponseBuffer(const BoundNetLog
& net_log
)
28 FtpCtrlResponseBuffer::~FtpCtrlResponseBuffer() {}
30 int FtpCtrlResponseBuffer::ConsumeData(const char* data
, int data_length
) {
31 buffer_
.append(data
, data_length
);
32 ExtractFullLinesFromBuffer();
34 while (!lines_
.empty()) {
35 ParsedLine line
= lines_
.front();
39 if (!line
.is_complete
|| line
.status_code
!= response_buf_
.status_code
) {
40 line_buf_
.append(line
.raw_text
);
44 response_buf_
.lines
.push_back(line_buf_
);
46 line_buf_
= line
.status_text
;
47 DCHECK_EQ(line
.status_code
, response_buf_
.status_code
);
49 if (!line
.is_multiline
) {
50 response_buf_
.lines
.push_back(line_buf_
);
51 responses_
.push(response_buf_
);
53 // Prepare to handle following lines.
54 response_buf_
= FtpCtrlResponse();
59 if (!line
.is_complete
)
60 return ERR_INVALID_RESPONSE
;
62 response_buf_
.status_code
= line
.status_code
;
63 if (line
.is_multiline
) {
64 line_buf_
= line
.status_text
;
67 response_buf_
.lines
.push_back(line
.status_text
);
68 responses_
.push(response_buf_
);
70 // Prepare to handle following lines.
71 response_buf_
= FtpCtrlResponse();
82 base::Value
* NetLogFtpCtrlResponseCallback(const FtpCtrlResponse
* response
,
83 NetLog::LogLevel log_level
) {
84 base::ListValue
* lines
= new base::ListValue();
85 lines
->AppendStrings(response
->lines
);
87 base::DictionaryValue
* dict
= new base::DictionaryValue();
88 dict
->SetInteger("status_code", response
->status_code
);
89 dict
->Set("lines", lines
);
95 FtpCtrlResponse
FtpCtrlResponseBuffer::PopResponse() {
96 FtpCtrlResponse result
= responses_
.front();
99 net_log_
.AddEvent(NetLog::TYPE_FTP_CONTROL_RESPONSE
,
100 base::Bind(&NetLogFtpCtrlResponseCallback
, &result
));
105 FtpCtrlResponseBuffer::ParsedLine::ParsedLine()
106 : has_status_code(false),
109 status_code(FtpCtrlResponse::kInvalidStatusCode
) {
113 FtpCtrlResponseBuffer::ParsedLine
FtpCtrlResponseBuffer::ParseLine(
114 const std::string
& line
) {
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;
130 if (result
.is_complete
) {
131 result
.status_text
= line
.substr(4);
133 result
.status_text
= line
;
136 result
.raw_text
= line
;
141 void FtpCtrlResponseBuffer::ExtractFullLinesFromBuffer() {
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)));
149 buffer_
.erase(0, cut_pos
);