Home | History | Annotate | Download | only in ftp
      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