• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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