1// Copyright (c) 2009 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 <string.h>
8
9#include "net/base/net_errors.h"
10#include "testing/gtest/include/gtest/gtest.h"
11
12namespace {
13
14class FtpCtrlResponseBufferTest : public testing::Test {
15 public:
16  FtpCtrlResponseBufferTest() : buffer_(net::BoundNetLog()) {
17  }
18
19 protected:
20  int PushDataToBuffer(const char* data) {
21    return buffer_.ConsumeData(data, strlen(data));
22  }
23
24  net::FtpCtrlResponseBuffer buffer_;
25};
26
27TEST_F(FtpCtrlResponseBufferTest, Basic) {
28  EXPECT_FALSE(buffer_.ResponseAvailable());
29
30  EXPECT_EQ(net::OK, PushDataToBuffer("200 Status Text\r\n"));
31  EXPECT_TRUE(buffer_.ResponseAvailable());
32
33  net::FtpCtrlResponse response = buffer_.PopResponse();
34  EXPECT_FALSE(buffer_.ResponseAvailable());
35  EXPECT_EQ(200, response.status_code);
36  ASSERT_EQ(1U, response.lines.size());
37  EXPECT_EQ("Status Text", response.lines[0]);
38}
39
40TEST_F(FtpCtrlResponseBufferTest, Chunks) {
41  EXPECT_EQ(net::OK, PushDataToBuffer("20"));
42  EXPECT_FALSE(buffer_.ResponseAvailable());
43  EXPECT_EQ(net::OK, PushDataToBuffer("0 Status"));
44  EXPECT_FALSE(buffer_.ResponseAvailable());
45  EXPECT_EQ(net::OK, PushDataToBuffer(" Text"));
46  EXPECT_FALSE(buffer_.ResponseAvailable());
47  EXPECT_EQ(net::OK, PushDataToBuffer("\r"));
48  EXPECT_FALSE(buffer_.ResponseAvailable());
49  EXPECT_EQ(net::OK, PushDataToBuffer("\n"));
50  EXPECT_TRUE(buffer_.ResponseAvailable());
51
52  net::FtpCtrlResponse response = buffer_.PopResponse();
53  EXPECT_FALSE(buffer_.ResponseAvailable());
54  EXPECT_EQ(200, response.status_code);
55  ASSERT_EQ(1U, response.lines.size());
56  EXPECT_EQ("Status Text", response.lines[0]);
57}
58
59TEST_F(FtpCtrlResponseBufferTest, Continuation) {
60  EXPECT_EQ(net::OK, PushDataToBuffer("230-FirstLine\r\n"));
61  EXPECT_FALSE(buffer_.ResponseAvailable());
62
63  EXPECT_EQ(net::OK, PushDataToBuffer("230-SecondLine\r\n"));
64  EXPECT_FALSE(buffer_.ResponseAvailable());
65
66  EXPECT_EQ(net::OK, PushDataToBuffer("230 LastLine\r\n"));
67  EXPECT_TRUE(buffer_.ResponseAvailable());
68
69  net::FtpCtrlResponse response = buffer_.PopResponse();
70  EXPECT_FALSE(buffer_.ResponseAvailable());
71  EXPECT_EQ(230, response.status_code);
72  ASSERT_EQ(3U, response.lines.size());
73  EXPECT_EQ("FirstLine", response.lines[0]);
74  EXPECT_EQ("SecondLine", response.lines[1]);
75  EXPECT_EQ("LastLine", response.lines[2]);
76}
77
78TEST_F(FtpCtrlResponseBufferTest, MultilineContinuation) {
79  EXPECT_EQ(net::OK, PushDataToBuffer("230-FirstLine\r\n"));
80  EXPECT_FALSE(buffer_.ResponseAvailable());
81
82  EXPECT_EQ(net::OK, PushDataToBuffer("Continued\r\n"));
83  EXPECT_FALSE(buffer_.ResponseAvailable());
84
85  EXPECT_EQ(net::OK, PushDataToBuffer("230-SecondLine\r\n"));
86  EXPECT_FALSE(buffer_.ResponseAvailable());
87
88  EXPECT_EQ(net::OK, PushDataToBuffer("215 Continued\r\n"));
89  EXPECT_FALSE(buffer_.ResponseAvailable());
90
91  EXPECT_EQ(net::OK, PushDataToBuffer("230 LastLine\r\n"));
92  EXPECT_TRUE(buffer_.ResponseAvailable());
93
94  net::FtpCtrlResponse response = buffer_.PopResponse();
95  EXPECT_FALSE(buffer_.ResponseAvailable());
96  EXPECT_EQ(230, response.status_code);
97  ASSERT_EQ(3U, response.lines.size());
98  EXPECT_EQ("FirstLineContinued", response.lines[0]);
99  EXPECT_EQ("SecondLine215 Continued", response.lines[1]);
100  EXPECT_EQ("LastLine", response.lines[2]);
101}
102
103TEST_F(FtpCtrlResponseBufferTest, MultilineContinuationZeroLength) {
104  // For the corner case from bug 29322.
105  EXPECT_EQ(net::OK, PushDataToBuffer("230-\r\n"));
106  EXPECT_FALSE(buffer_.ResponseAvailable());
107
108  EXPECT_EQ(net::OK, PushDataToBuffer("example.com\r\n"));
109  EXPECT_FALSE(buffer_.ResponseAvailable());
110
111  EXPECT_EQ(net::OK, PushDataToBuffer("230 LastLine\r\n"));
112  EXPECT_TRUE(buffer_.ResponseAvailable());
113
114  net::FtpCtrlResponse response = buffer_.PopResponse();
115  EXPECT_FALSE(buffer_.ResponseAvailable());
116  EXPECT_EQ(230, response.status_code);
117  ASSERT_EQ(2U, response.lines.size());
118  EXPECT_EQ("example.com", response.lines[0]);
119  EXPECT_EQ("LastLine", response.lines[1]);
120}
121
122TEST_F(FtpCtrlResponseBufferTest, SimilarContinuation) {
123  EXPECT_EQ(net::OK, PushDataToBuffer("230-FirstLine\r\n"));
124  EXPECT_FALSE(buffer_.ResponseAvailable());
125
126  // Notice the space at the start of the line. It should be recognized
127  // as a continuation, and not the last line.
128  EXPECT_EQ(net::OK, PushDataToBuffer(" 230 Continued\r\n"));
129  EXPECT_FALSE(buffer_.ResponseAvailable());
130
131  EXPECT_EQ(net::OK, PushDataToBuffer("230 TrueLastLine\r\n"));
132  EXPECT_TRUE(buffer_.ResponseAvailable());
133
134  net::FtpCtrlResponse response = buffer_.PopResponse();
135  EXPECT_FALSE(buffer_.ResponseAvailable());
136  EXPECT_EQ(230, response.status_code);
137  ASSERT_EQ(2U, response.lines.size());
138  EXPECT_EQ("FirstLine 230 Continued", response.lines[0]);
139  EXPECT_EQ("TrueLastLine", response.lines[1]);
140}
141
142// The nesting of multi-line responses is not allowed.
143TEST_F(FtpCtrlResponseBufferTest, NoNesting) {
144  EXPECT_EQ(net::OK, PushDataToBuffer("230-FirstLine\r\n"));
145  EXPECT_FALSE(buffer_.ResponseAvailable());
146
147  EXPECT_EQ(net::OK, PushDataToBuffer("300-Continuation\r\n"));
148  EXPECT_FALSE(buffer_.ResponseAvailable());
149
150  EXPECT_EQ(net::OK, PushDataToBuffer("300 Still continuation\r\n"));
151  EXPECT_FALSE(buffer_.ResponseAvailable());
152
153  EXPECT_EQ(net::OK, PushDataToBuffer("230 Real End\r\n"));
154  ASSERT_TRUE(buffer_.ResponseAvailable());
155
156  net::FtpCtrlResponse response = buffer_.PopResponse();
157  EXPECT_FALSE(buffer_.ResponseAvailable());
158  EXPECT_EQ(230, response.status_code);
159  ASSERT_EQ(2U, response.lines.size());
160  EXPECT_EQ("FirstLine300-Continuation300 Still continuation",
161            response.lines[0]);
162  EXPECT_EQ("Real End", response.lines[1]);
163}
164
165TEST_F(FtpCtrlResponseBufferTest, NonNumericResponse) {
166  EXPECT_EQ(net::ERR_INVALID_RESPONSE, PushDataToBuffer("Non-numeric\r\n"));
167  EXPECT_FALSE(buffer_.ResponseAvailable());
168}
169
170TEST_F(FtpCtrlResponseBufferTest, OutOfRangeResponse) {
171  EXPECT_EQ(net::ERR_INVALID_RESPONSE, PushDataToBuffer("777 OK?\r\n"));
172  EXPECT_FALSE(buffer_.ResponseAvailable());
173}
174
175}  // namespace
176