1 // Copyright (c) 2009 The Chromium Authors. All rights reserved. Use of this
2 // source code is governed by a BSD-style license that can be found in the
3 // LICENSE file.
4
5 #include "net/ftp/ftp_ctrl_response_buffer.h"
6
7 #include "base/logging.h"
8 #include "base/string_number_conversions.h"
9 //#include "base/string_util.h"
10 #include "net/base/net_errors.h"
11
12 namespace net {
13
14 // static
15 const int FtpCtrlResponse::kInvalidStatusCode = -1;
16
FtpCtrlResponse()17 FtpCtrlResponse::FtpCtrlResponse() : status_code(kInvalidStatusCode) {}
18
~FtpCtrlResponse()19 FtpCtrlResponse::~FtpCtrlResponse() {}
20
FtpCtrlResponseBuffer()21 FtpCtrlResponseBuffer::FtpCtrlResponseBuffer() : multiline_(false) {}
22
~FtpCtrlResponseBuffer()23 FtpCtrlResponseBuffer::~FtpCtrlResponseBuffer() {}
24
ConsumeData(const char * data,int data_length)25 int FtpCtrlResponseBuffer::ConsumeData(const char* data, int data_length) {
26 buffer_.append(data, data_length);
27 ExtractFullLinesFromBuffer();
28
29 while (!lines_.empty()) {
30 ParsedLine line = lines_.front();
31 lines_.pop();
32
33 if (multiline_) {
34 if (!line.is_complete || line.status_code != response_buf_.status_code) {
35 line_buf_.append(line.raw_text);
36 continue;
37 }
38
39 response_buf_.lines.push_back(line_buf_);
40
41 line_buf_ = line.status_text;
42 DCHECK_EQ(line.status_code, response_buf_.status_code);
43
44 if (!line.is_multiline) {
45 response_buf_.lines.push_back(line_buf_);
46 responses_.push(response_buf_);
47
48 // Prepare to handle following lines.
49 response_buf_ = FtpCtrlResponse();
50 line_buf_.clear();
51 multiline_ = false;
52 }
53 } else {
54 if (!line.is_complete)
55 return ERR_INVALID_RESPONSE;
56
57 response_buf_.status_code = line.status_code;
58 if (line.is_multiline) {
59 line_buf_ = line.status_text;
60 multiline_ = true;
61 } else {
62 response_buf_.lines.push_back(line.status_text);
63 responses_.push(response_buf_);
64
65 // Prepare to handle following lines.
66 response_buf_ = FtpCtrlResponse();
67 line_buf_.clear();
68 }
69 }
70 }
71
72 return OK;
73 }
74
PopResponse()75 FtpCtrlResponse FtpCtrlResponseBuffer::PopResponse() {
76 FtpCtrlResponse result = responses_.front();
77 responses_.pop();
78 return result;
79 }
80
ParsedLine()81 FtpCtrlResponseBuffer::ParsedLine::ParsedLine()
82 : has_status_code(false),
83 is_multiline(false),
84 is_complete(false),
85 status_code(FtpCtrlResponse::kInvalidStatusCode) {
86 }
87
88 // static
ParseLine(const std::string & line)89 FtpCtrlResponseBuffer::ParsedLine FtpCtrlResponseBuffer::ParseLine(
90 const std::string& line) {
91 ParsedLine result;
92
93 if (line.length() >= 3) {
94 if (base::StringToInt(line.begin(), line.begin() + 3, &result.status_code))
95 result.has_status_code = (100 <= result.status_code &&
96 result.status_code <= 599);
97 if (result.has_status_code && line.length() >= 4 && line[3] == ' ') {
98 result.is_complete = true;
99 } else if (result.has_status_code && line.length() >= 4 && line[3] == '-') {
100 result.is_complete = true;
101 result.is_multiline = true;
102 }
103 }
104
105 if (result.is_complete) {
106 result.status_text = line.substr(4);
107 } else {
108 result.status_text = line;
109 }
110
111 result.raw_text = line;
112
113 return result;
114 }
115
ExtractFullLinesFromBuffer()116 void FtpCtrlResponseBuffer::ExtractFullLinesFromBuffer() {
117 int cut_pos = 0;
118 for (size_t i = 0; i < buffer_.length(); i++) {
119 if (i >= 1 && buffer_[i - 1] == '\r' && buffer_[i] == '\n') {
120 lines_.push(ParseLine(buffer_.substr(cut_pos, i - cut_pos - 1)));
121 cut_pos = i + 1;
122 }
123 }
124 buffer_.erase(0, cut_pos);
125 }
126
127 } // namespace net
128