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