• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
FtpCtrlResponse()19 FtpCtrlResponse::FtpCtrlResponse() : status_code(kInvalidStatusCode) {}
20 
~FtpCtrlResponse()21 FtpCtrlResponse::~FtpCtrlResponse() {}
22 
FtpCtrlResponseBuffer(const BoundNetLog & net_log)23 FtpCtrlResponseBuffer::FtpCtrlResponseBuffer(const BoundNetLog& net_log)
24     : multiline_(false),
25       net_log_(net_log) {
26 }
27 
~FtpCtrlResponseBuffer()28 FtpCtrlResponseBuffer::~FtpCtrlResponseBuffer() {}
29 
ConsumeData(const char * data,int data_length)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 
NetLogFtpCtrlResponseCallback(const FtpCtrlResponse * response,NetLog::LogLevel log_level)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 
PopResponse()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 
ParsedLine()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
ParseLine(const std::string & line)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 
ExtractFullLinesFromBuffer()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
153