Updating trunk VERSION from 2139.0 to 2140.0
[chromium-blink-merge.git] / net / ftp / ftp_ctrl_response_buffer.cc
blobf7b14678095a7ecfa9bea48b832b79dd98cd498f
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"
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"
14 namespace net {
16 // static
17 const int FtpCtrlResponse::kInvalidStatusCode = -1;
19 FtpCtrlResponse::FtpCtrlResponse() : status_code(kInvalidStatusCode) {}
21 FtpCtrlResponse::~FtpCtrlResponse() {}
23 FtpCtrlResponseBuffer::FtpCtrlResponseBuffer(const BoundNetLog& net_log)
24 : multiline_(false),
25 net_log_(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();
36 lines_.pop();
38 if (multiline_) {
39 if (!line.is_complete || line.status_code != response_buf_.status_code) {
40 line_buf_.append(line.raw_text);
41 continue;
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();
55 line_buf_.clear();
56 multiline_ = false;
58 } else {
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;
65 multiline_ = true;
66 } else {
67 response_buf_.lines.push_back(line.status_text);
68 responses_.push(response_buf_);
70 // Prepare to handle following lines.
71 response_buf_ = FtpCtrlResponse();
72 line_buf_.clear();
77 return OK;
80 namespace {
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);
90 return dict;
93 } // namespace
95 FtpCtrlResponse FtpCtrlResponseBuffer::PopResponse() {
96 FtpCtrlResponse result = responses_.front();
97 responses_.pop();
99 net_log_.AddEvent(NetLog::TYPE_FTP_CONTROL_RESPONSE,
100 base::Bind(&NetLogFtpCtrlResponseCallback, &result));
102 return result;
105 FtpCtrlResponseBuffer::ParsedLine::ParsedLine()
106 : has_status_code(false),
107 is_multiline(false),
108 is_complete(false),
109 status_code(FtpCtrlResponse::kInvalidStatusCode) {
112 // static
113 FtpCtrlResponseBuffer::ParsedLine FtpCtrlResponseBuffer::ParseLine(
114 const std::string& line) {
115 ParsedLine result;
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);
132 } else {
133 result.status_text = line;
136 result.raw_text = line;
138 return result;
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;
149 buffer_.erase(0, cut_pos);
152 } // namespace net