1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17 package org.apache.commons.net.tftp;
18
19 import static org.junit.jupiter.api.Assertions.assertEquals;
20 import static org.junit.jupiter.api.Assertions.assertFalse;
21 import static org.junit.jupiter.api.Assertions.assertThrows;
22 import static org.junit.jupiter.api.Assertions.fail;
23
24 import java.io.IOException;
25 import java.io.InputStream;
26 import java.io.OutputStream;
27 import java.nio.charset.StandardCharsets;
28 import java.nio.file.Files;
29 import java.nio.file.Path;
30 import java.time.Duration;
31 import java.util.UUID;
32
33 import org.apache.commons.io.FileUtils;
34 import org.apache.commons.net.tftp.TFTPServer.ServerMode;
35 import org.junit.jupiter.api.AfterEach;
36 import org.junit.jupiter.api.BeforeEach;
37 import org.junit.jupiter.api.Test;
38
39
40
41
42
43 public class TFTPServerPathTest {
44
45 private static final int SERVER_PORT = 6901;
46 private static final String FILE_PREFIX = "TFTPServerPathTest_";
47
48 private static Path createFileInDir(final Path directory, final String fileName) throws IOException {
49 final Path filePath = directory.resolve(fileName);
50 if (Files.exists(filePath)) {
51 Files.delete(filePath);
52 }
53 return Files.createFile(filePath);
54 }
55
56 private static void deleteFile(final Path path, final boolean retry) throws IOException {
57 if (path != null) {
58 try {
59 Files.deleteIfExists(path);
60 } catch (IOException e) {
61 if (retry) {
62 try {
63 Thread.sleep(500);
64 } catch (InterruptedException e1) {
65 fail(e);
66 }
67 Files.deleteIfExists(path);
68 }
69 throw e;
70 }
71 }
72 }
73
74 private static String getRandomFileName(final String suffix) {
75 return FILE_PREFIX + UUID.randomUUID() + suffix;
76 }
77
78 private TFTPServer tftpServer;
79 private Path serverDirectory;
80
81 private TFTPClient tftpClient;
82 private Path fileToRead;
83 private Path fileToWrite;
84
85 @AfterEach
86 public void afterEach() throws IOException {
87 if (tftpClient != null) {
88 tftpClient.close();
89 }
90 if (tftpServer != null) {
91 tftpServer.close();
92 }
93 deleteFile(fileToRead, true);
94 deleteFile(fileToWrite, true);
95 }
96
97 @BeforeEach
98 public void beforeEach() throws IOException {
99 serverDirectory = FileUtils.getTempDirectory().toPath();
100 fileToRead = createFileInDir(serverDirectory, getRandomFileName(".source.txt"));
101 fileToWrite = createFileInDir(serverDirectory, getRandomFileName(".out"));
102 }
103
104 private TFTPServer startTftpServer(final ServerMode serverMode) throws IOException {
105 return new TFTPServer(serverDirectory.toFile(), serverDirectory.toFile(), SERVER_PORT, serverMode, null, null);
106 }
107
108 @Test
109 public void testReadOnly() throws IOException {
110
111 tftpServer = startTftpServer(ServerMode.GET_ONLY);
112 final String serverAddress = "localhost";
113 final int serverPort = tftpServer.getPort();
114
115
116 Files.write(fileToRead, "The quick brown fox jumps over the lazy dog".getBytes(StandardCharsets.UTF_8));
117 final long fileToReadContentLength = Files.size(fileToRead);
118
119 tftpClient = new TFTPClient();
120 tftpClient.open();
121 tftpClient.setSoTimeout(Duration.ofMillis(2000));
122
123
124 try (final OutputStream os = Files.newOutputStream(fileToWrite)) {
125 final String writeFileName = fileToRead.getFileName().toString();
126 final int bytesRead = tftpClient.receiveFile(writeFileName, TFTP.BINARY_MODE, os, serverAddress, serverPort);
127 assertEquals(fileToReadContentLength, bytesRead);
128 }
129
130
131 try (final InputStream is = Files.newInputStream(fileToRead)) {
132 final String readFileName = fileToRead.getFileName().toString();
133 final IOException exception = assertThrows(IOException.class, () -> tftpClient.sendFile(readFileName, TFTP.BINARY_MODE, is, serverAddress, serverPort));
134 assertEquals("Error code 4 received: Write not allowed by server.", exception.getMessage());
135 }
136 }
137
138 @Test
139 public void testWriteOnly() throws IOException {
140
141 tftpServer = startTftpServer(ServerMode.PUT_ONLY);
142 final String serverAddress = "localhost";
143 final int serverPort = tftpServer.getPort();
144
145 tftpClient = new TFTPClient();
146 tftpClient.open();
147 tftpClient.setSoTimeout(Duration.ofMillis(2000));
148
149
150 try (final OutputStream os = Files.newOutputStream(fileToWrite)) {
151 final String readFileName = fileToRead.getFileName().toString();
152 final IOException exception = assertThrows(IOException.class, () -> tftpClient.receiveFile(readFileName, TFTP.BINARY_MODE, os, serverAddress, serverPort));
153 assertEquals("Error code 4 received: Read not allowed by server.", exception.getMessage());
154 }
155
156
157 try (final InputStream is = Files.newInputStream(fileToRead)) {
158 deleteFile(fileToWrite, false);
159 final String writeFileName = fileToWrite.getFileName().toString();
160 tftpClient.sendFile(writeFileName, TFTP.BINARY_MODE, is, serverAddress, serverPort);
161 }
162 }
163
164 @Test
165 public void testWriteOutsideHome() throws IOException {
166
167 tftpServer = startTftpServer(ServerMode.GET_AND_PUT);
168 final String serverAddress = "localhost";
169 final int serverPort = tftpServer.getPort();
170
171 tftpClient = new TFTPClient();
172 tftpClient.open();
173
174 try (final InputStream is = Files.newInputStream(fileToRead)) {
175 final IOException exception = assertThrows(IOException.class, () -> tftpClient.sendFile("../foo", TFTP.BINARY_MODE, is, serverAddress, serverPort));
176 assertEquals("Error code 0 received: Cannot access files outside of TFTP server root.", exception.getMessage());
177 assertFalse(Files.exists(serverDirectory.resolve("foo")), "file created when it should not have been");
178 }
179 }
180
181 @Test
182 public void testWriteVerifyContents() throws IOException {
183
184 tftpServer = startTftpServer(ServerMode.GET_AND_PUT);
185 final String serverAddress = "localhost";
186 final int serverPort = tftpServer.getPort();
187
188 tftpClient = new TFTPClient();
189 tftpClient.open();
190 tftpClient.setSoTimeout(Duration.ofMillis(2000));
191
192
193 final byte[] content = "TFTP write test!".getBytes(StandardCharsets.UTF_8);
194 Files.write(fileToRead, content);
195
196
197 try (final InputStream is = Files.newInputStream(fileToRead)) {
198 deleteFile(fileToWrite, false);
199 final String writeFileName = fileToWrite.getFileName().toString();
200 tftpClient.sendFile(writeFileName, TFTP.BINARY_MODE, is, serverAddress, serverPort);
201 }
202
203
204 try (final OutputStream os = Files.newOutputStream(fileToWrite)) {
205 final String readFileName = fileToRead.getFileName().toString();
206 final int readBytes = tftpClient.receiveFile(readFileName, TFTP.BINARY_MODE, os, serverAddress, serverPort);
207 assertEquals(content.length, readBytes);
208 }
209 }
210
211 }