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 17 FtpCtrlResponse::FtpCtrlResponse() : status_code(kInvalidStatusCode) {} 18 19 FtpCtrlResponse::~FtpCtrlResponse() {} 20 21 FtpCtrlResponseBuffer::FtpCtrlResponseBuffer() : multiline_(false) {} 22 23 FtpCtrlResponseBuffer::~FtpCtrlResponseBuffer() {} 24 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 75 FtpCtrlResponse FtpCtrlResponseBuffer::PopResponse() { 76 FtpCtrlResponse result = responses_.front(); 77 responses_.pop(); 78 return result; 79 } 80 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 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 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