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 scoped_ptr
<base::Value
> NetLogFtpCtrlResponseCallback(
83 const FtpCtrlResponse
* response
,
84 NetLogCaptureMode capture_mode
) {
85 scoped_ptr
<base::ListValue
> lines(new base::ListValue());
86 lines
->AppendStrings(response
->lines
);
88 scoped_ptr
<base::DictionaryValue
> dict(new base::DictionaryValue());
89 dict
->SetInteger("status_code", response
->status_code
);
90 dict
->Set("lines", lines
.Pass());
96 FtpCtrlResponse
FtpCtrlResponseBuffer::PopResponse() {
97 FtpCtrlResponse result
= responses_
.front();
100 net_log_
.AddEvent(NetLog::TYPE_FTP_CONTROL_RESPONSE
,
101 base::Bind(&NetLogFtpCtrlResponseCallback
, &result
));
106 FtpCtrlResponseBuffer::ParsedLine::ParsedLine()
107 : has_status_code(false),
110 status_code(FtpCtrlResponse::kInvalidStatusCode
) {
114 FtpCtrlResponseBuffer::ParsedLine
FtpCtrlResponseBuffer::ParseLine(
115 const std::string
& line
) {
118 if (line
.length() >= 3) {
119 if (base::StringToInt(base::StringPiece(line
.begin(), line
.begin() + 3),
120 &result
.status_code
))
121 result
.has_status_code
= (100 <= result
.status_code
&&
122 result
.status_code
<= 599);
123 if (result
.has_status_code
&& line
.length() >= 4 && line
[3] == ' ') {
124 result
.is_complete
= true;
125 } else if (result
.has_status_code
&& line
.length() >= 4 && line
[3] == '-') {
126 result
.is_complete
= true;
127 result
.is_multiline
= true;
131 if (result
.is_complete
) {
132 result
.status_text
= line
.substr(4);
134 result
.status_text
= line
;
137 result
.raw_text
= line
;
142 void FtpCtrlResponseBuffer::ExtractFullLinesFromBuffer() {
144 for (size_t i
= 0; i
< buffer_
.length(); i
++) {
145 if (i
>= 1 && buffer_
[i
- 1] == '\r' && buffer_
[i
] == '\n') {
146 lines_
.push(ParseLine(buffer_
.substr(cut_pos
, i
- cut_pos
- 1)));
150 buffer_
.erase(0, cut_pos
);