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.
4
5#include "net/ftp/ftp_directory_listing_parser_unittest.h"
6
7#include "base/format_macros.h"
8#include "base/strings/string_util.h"
9#include "base/strings/stringprintf.h"
10#include "net/ftp/ftp_directory_listing_parser_ls.h"
11
12namespace net {
13
14namespace {
15
16typedef FtpDirectoryListingParserTest FtpDirectoryListingParserLsTest;
17
18TEST_F(FtpDirectoryListingParserLsTest, Good) {
19  const struct SingleLineTestData good_cases[] = {
20    { "-rw-r--r--    1 ftp      ftp           528 Nov 01  2007 README",
21      FtpDirectoryListingEntry::FILE, "README", 528,
22      2007, 11, 1, 0, 0 },
23    { "drwxr-xr-x    3 ftp      ftp          4096 May 15 18:11 directory",
24      FtpDirectoryListingEntry::DIRECTORY, "directory", -1,
25      1994, 5, 15, 18, 11 },
26    { "lrwxrwxrwx 1 0  0 26 Sep 18 2008 pub -> vol/1/.CLUSTER/var_ftp/pub",
27      FtpDirectoryListingEntry::SYMLINK, "pub", -1,
28      2008, 9, 18, 0, 0 },
29    { "lrwxrwxrwx 1 0  0 3 Oct 12 13:37 mirror -> pub",
30      FtpDirectoryListingEntry::SYMLINK, "mirror", -1,
31      1994, 10, 12, 13, 37 },
32    { "drwxrwsr-x    4 501      501          4096 Feb 20  2007 pub",
33      FtpDirectoryListingEntry::DIRECTORY, "pub", -1,
34      2007, 2, 20, 0, 0 },
35    { "drwxr-xr-x   4 (?)      (?)          4096 Apr  8  2007 jigdo",
36      FtpDirectoryListingEntry::DIRECTORY, "jigdo", -1,
37      2007, 4, 8, 0, 0 },
38    { "drwx-wx-wt  2 root  wheel  512 Jul  1 02:15 incoming",
39      FtpDirectoryListingEntry::DIRECTORY, "incoming", -1,
40      1994, 7, 1, 2, 15 },
41    { "-rw-r--r-- 1 2 3 3447432 May 18  2009 Foo - Manual.pdf",
42      FtpDirectoryListingEntry::FILE, "Foo - Manual.pdf", 3447432,
43      2009, 5, 18, 0, 0 },
44    { "d-wx-wx-wt+  4 ftp      989          512 Dec  8 15:54 incoming",
45      FtpDirectoryListingEntry::DIRECTORY, "incoming", -1,
46      1993, 12, 8, 15, 54 },
47    { "drwxrwxrwx   1 owner    group               1024 Sep 13  0:30 audio",
48      FtpDirectoryListingEntry::DIRECTORY, "audio", -1,
49      1994, 9, 13, 0, 30 },
50    { "lrwxrwxrwx 1 0  0 26 Sep 18 2008 pub",
51      FtpDirectoryListingEntry::SYMLINK, "pub", -1,
52      2008, 9, 18, 0, 0 },
53    { "-rw-r--r--    1 ftp      ftp           -528 Nov 01  2007 README",
54      FtpDirectoryListingEntry::FILE, "README", -1,
55      2007, 11, 1, 0, 0 },
56
57    // Tests for the wu-ftpd variant:
58    { "drwxr-xr-x   2 sys          512 Mar 27  2009 pub",
59      FtpDirectoryListingEntry::DIRECTORY, "pub", -1,
60      2009, 3, 27, 0, 0 },
61    { "lrwxrwxrwx 0  0 26 Sep 18 2008 pub -> vol/1/.CLUSTER/var_ftp/pub",
62      FtpDirectoryListingEntry::SYMLINK, "pub", -1,
63      2008, 9, 18, 0, 0 },
64    { "drwxr-xr-x   (?)      (?)          4096 Apr  8  2007 jigdo",
65      FtpDirectoryListingEntry::DIRECTORY, "jigdo", -1,
66      2007, 4, 8, 0, 0 },
67    { "-rw-r--r-- 2 3 3447432 May 18  2009 Foo - Manual.pdf",
68      FtpDirectoryListingEntry::FILE, "Foo - Manual.pdf", 3447432,
69      2009, 5, 18, 0, 0 },
70
71    // Tests for "ls -l" style listings sent by an OS/2 server (FtpServer):
72    { "-r--r--r--  1 ftp      -A---       13274 Mar  1  2006 UpTime.exe",
73      FtpDirectoryListingEntry::FILE, "UpTime.exe", 13274,
74      2006, 3, 1, 0, 0 },
75    { "dr--r--r--  1 ftp      -----           0 Nov 17 17:08 kernels",
76      FtpDirectoryListingEntry::DIRECTORY, "kernels", -1,
77      1993, 11, 17, 17, 8 },
78
79    // Tests for "ls -l" style listing sent by Xplain FTP Server.
80    { "drwxr-xr-x               folder        0 Jul 17  2006 online",
81      FtpDirectoryListingEntry::DIRECTORY, "online", -1,
82      2006, 7, 17, 0, 0 },
83
84    // Tests for "ls -l" style listing with owning group name
85    // not separated from file size (http://crbug.com/58963).
86    { "-rw-r--r-- 1 ftpadmin ftpadmin125435904 Apr  9  2008 .pureftpd-upload",
87      FtpDirectoryListingEntry::FILE, ".pureftpd-upload", 0,
88      2008, 4, 9, 0, 0 },
89
90    // Tests for "ls -l" style listing with number of links
91    // not separated from permission listing (http://crbug.com/70394).
92    { "drwxr-xr-x1732 266      111        90112 Jun 21  2001 .rda_2",
93      FtpDirectoryListingEntry::DIRECTORY, ".rda_2", -1,
94      2001, 6, 21, 0, 0 },
95
96    // Tests for "ls -l" style listing with group name containing spaces.
97    { "drwxrwxr-x   3 %%%%     Domain Users     4096 Dec  9  2009 %%%%%",
98      FtpDirectoryListingEntry::DIRECTORY, "%%%%%", -1,
99      2009, 12, 9, 0, 0 },
100
101    // Tests for "ls -l" style listing in Russian locale (note the swapped
102    // parts order: the day of month is the first, before month).
103    { "-rwxrwxr-x 1 ftp ftp 123 23 \xd0\xbc\xd0\xb0\xd0\xb9 2011 test",
104      FtpDirectoryListingEntry::FILE, "test", 123,
105      2011, 5, 23, 0, 0 },
106    { "drwxrwxr-x 1 ftp ftp 4096 19 \xd0\xbe\xd0\xba\xd1\x82 2011 dir",
107      FtpDirectoryListingEntry::DIRECTORY, "dir", -1,
108      2011, 10, 19, 0, 0 },
109
110    // Plan9 sends entry type "a" for append-only files.
111    { "ar-xr-xr-x   2 none     none         512 Apr 26 17:52 plan9",
112      FtpDirectoryListingEntry::FILE, "plan9", 512,
113      1994, 4, 26, 17, 52 },
114
115    // Hylafax sends a shorter permission listing.
116    { "drwxrwx   2       10     4096 Jul 28 02:41 tmp",
117      FtpDirectoryListingEntry::DIRECTORY, "tmp", -1,
118      1994, 7, 28, 2, 41 },
119
120    // Completely different date format (YYYY-MM-DD).
121    { "drwxrwxrwx 2 root root  4096 2012-02-07 00:31 notas_servico",
122      FtpDirectoryListingEntry::DIRECTORY, "notas_servico", -1,
123      2012, 2, 7, 0, 31 },
124    { "-rwxrwxrwx 2 root root  4096 2012-02-07 00:31 notas_servico",
125      FtpDirectoryListingEntry::FILE, "notas_servico", 4096,
126      2012, 2, 7, 0, 31 },
127
128    // Weird permission bits.
129    { "drwx--l---   2 0        10           512 Dec 22  1994 swetzel",
130      FtpDirectoryListingEntry::DIRECTORY, "swetzel", -1,
131      1994, 12, 22, 0, 0 },
132
133    { "drwxrwxr-x   1 500     244         660 Jan  1 00:0 bin",
134      FtpDirectoryListingEntry::DIRECTORY, "bin", -1,
135      1994, 1, 1, 0, 0 },
136
137    // Garbage in date (but still parseable).
138    { "lrw-rw-rw-   1 user     group         542 "
139      "/t11/member/incomingFeb  8  2007 "
140      "Shortcut to incoming.lnk -> /t11/member/incoming",
141      FtpDirectoryListingEntry::SYMLINK, "Shortcut to incoming.lnk", -1,
142      2007, 2, 8, 0, 0 },
143
144    // Garbage in permissions (with no effect on other bits).
145    // Also test multiple "columns" resulting from the garbage.
146    { "garbage    1 ftp      ftp           528 Nov 01  2007 README",
147      FtpDirectoryListingEntry::FILE, "README", 528,
148      2007, 11, 1, 0, 0 },
149    { "gar bage    1 ftp      ftp           528 Nov 01  2007 README",
150      FtpDirectoryListingEntry::FILE, "README", 528,
151      2007, 11, 1, 0, 0 },
152    { "g a r b a g e    1 ftp      ftp           528 Nov 01  2007 README",
153      FtpDirectoryListingEntry::FILE, "README", 528,
154      2007, 11, 1, 0, 0 },
155  };
156  for (size_t i = 0; i < arraysize(good_cases); i++) {
157    SCOPED_TRACE(base::StringPrintf("Test[%" PRIuS "]: %s", i,
158                                    good_cases[i].input));
159
160    std::vector<FtpDirectoryListingEntry> entries;
161    EXPECT_TRUE(ParseFtpDirectoryListingLs(
162        GetSingleLineTestCase(good_cases[i].input),
163        GetMockCurrentTime(),
164        &entries));
165    VerifySingleLineTestCase(good_cases[i], entries);
166  }
167}
168
169TEST_F(FtpDirectoryListingParserLsTest, Ignored) {
170  const char* ignored_cases[] = {
171    "drwxr-xr-x 2 0 0 4096 Mar 18  2007  ",  // http://crbug.com/60065
172
173    "ftpd: .: Permission denied",
174    "ftpd-BSD: .: Permission denied",
175    "ls: .: EDC5111I Permission denied.",
176
177    // Tests important for security: verify that after we detect the column
178    // offset we don't try to access invalid memory on malformed input.
179    "drwxr-xr-x 3 ftp ftp 4096 May 15 18:11",
180    "drwxr-xr-x 3 ftp     4096 May 15 18:11",
181    "drwxr-xr-x   folder     0 May 15 18:11",
182  };
183  for (size_t i = 0; i < arraysize(ignored_cases); i++) {
184    SCOPED_TRACE(base::StringPrintf("Test[%" PRIuS "]: %s", i,
185                                    ignored_cases[i]));
186
187    std::vector<FtpDirectoryListingEntry> entries;
188    EXPECT_TRUE(ParseFtpDirectoryListingLs(
189                    GetSingleLineTestCase(ignored_cases[i]),
190                    GetMockCurrentTime(),
191                    &entries));
192    EXPECT_EQ(0U, entries.size());
193  }
194}
195
196TEST_F(FtpDirectoryListingParserLsTest, Bad) {
197  const char* bad_cases[] = {
198    " foo",
199    "garbage",
200    "-rw-r--r-- ftp ftp",
201    "-rw-r--r-- ftp ftp 528 Foo 01 2007 README",
202    "-rw-r--r-- 1 ftp ftp",
203    "-rw-r--r-- 1 ftp ftp 528 Foo 01 2007 README",
204
205    // Invalid month value (30).
206    "drwxrwxrwx 2 root root  4096 2012-30-07 00:31 notas_servico",
207  };
208  for (size_t i = 0; i < arraysize(bad_cases); i++) {
209    SCOPED_TRACE(base::StringPrintf("Test[%" PRIuS "]: %s", i,
210                                    bad_cases[i]));
211
212    std::vector<FtpDirectoryListingEntry> entries;
213    EXPECT_FALSE(ParseFtpDirectoryListingLs(GetSingleLineTestCase(bad_cases[i]),
214                                            GetMockCurrentTime(),
215                                            &entries));
216  }
217}
218
219}  // namespace
220
221}  // namespace net
222