blob: 3871d0ccec6765d4601d545f042e6abd2e04ddd7 [file] [log] [blame]
J. Duke319a3b92007-12-01 00:00:00 +00001/*
2 * Copyright 2002 Sun Microsystems, Inc. All Rights Reserved.
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4 *
5 * This code is free software; you can redistribute it and/or modify it
6 * under the terms of the GNU General Public License version 2 only, as
7 * published by the Free Software Foundation.
8 *
9 * This code is distributed in the hope that it will be useful, but WITHOUT
10 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
11 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
12 * version 2 for more details (a copy is included in the LICENSE file that
13 * accompanied this code).
14 *
15 * You should have received a copy of the GNU General Public License version
16 * 2 along with this work; if not, write to the Free Software Foundation,
17 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
18 *
19 * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
20 * CA 95054 USA or visit www.sun.com if you need additional information or
21 * have any questions.
22 */
23
24/*
25 *
26 * run from MarkResetTest.sh
27 */
28
29import java.io.*;
30import java.net.*;
31import java.util.regex.*;
32
33public class MarkResetTest {
34
35 /**
36 * A class that simulates, on a separate, an FTP server.
37 */
38 private class FtpServer extends Thread {
39 private ServerSocket server;
40 private int port;
41 private boolean done = false;
42 private boolean pasvEnabled = true;
43 private boolean portEnabled = true;
44 private boolean extendedEnabled = true;
45
46 /**
47 * This Inner class will handle ONE client at a time.
48 * That's where 99% of the protocol handling is done.
49 */
50
51 private class FtpServerHandler extends Thread {
52 BufferedReader in;
53 PrintWriter out;
54 Socket client;
55 private final int ERROR = 0;
56 private final int USER = 1;
57 private final int PASS = 2;
58 private final int CWD = 3;
59 private final int TYPE = 4;
60 private final int RETR = 5;
61 private final int PASV = 6;
62 private final int PORT = 7;
63 private final int QUIT = 8;
64 private final int EPSV = 9;
65 String[] cmds = { "USER", "PASS", "CWD",
66 "TYPE", "RETR", "PASV",
67 "PORT", "QUIT", "EPSV"};
68 private String arg = null;
69 private ServerSocket pasv = null;
70 private int data_port = 0;
71 private InetAddress data_addr = null;
72
73 /**
74 * Parses a line to match it with one of the supported FTP commands.
75 * Returns the command number.
76 */
77
78 private int parseCmd(String cmd) {
79 if (cmd == null || cmd.length() < 3)
80 return ERROR;
81 int blank = cmd.indexOf(' ');
82 if (blank < 0)
83 blank = cmd.length();
84 if (blank < 3)
85 return ERROR;
86 String s = cmd.substring(0, blank);
87 if (cmd.length() > blank+1)
88 arg = cmd.substring(blank+1, cmd.length());
89 else
90 arg = null;
91 for (int i = 0; i < cmds.length; i++) {
92 if (s.equalsIgnoreCase(cmds[i]))
93 return i+1;
94 }
95 return ERROR;
96 }
97
98 public FtpServerHandler(Socket cl) {
99 client = cl;
100 }
101
102 protected boolean isPasvSet() {
103 if (pasv != null && !pasvEnabled) {
104 try {
105 pasv.close();
106 } catch (IOException ex) {
107 }
108 pasv = null;
109 }
110 if (pasvEnabled && pasv != null)
111 return true;
112 return false;
113 }
114
115 /**
116 * Open the data socket with the client. This can be the
117 * result of a "PASV" or "PORT" command.
118 */
119
120 protected OutputStream getOutDataStream() {
121 try {
122 if (isPasvSet()) {
123 Socket s = pasv.accept();
124 return s.getOutputStream();
125 }
126 if (data_addr != null) {
127 Socket s = new Socket(data_addr, data_port);
128 data_addr = null;
129 data_port = 0;
130 return s.getOutputStream();
131 }
132 } catch (Exception e) {
133 e.printStackTrace();
134 }
135 return null;
136 }
137
138 protected InputStream getInDataStream() {
139 try {
140 if (isPasvSet()) {
141 Socket s = pasv.accept();
142 return s.getInputStream();
143 }
144 if (data_addr != null) {
145 Socket s = new Socket(data_addr, data_port);
146 data_addr = null;
147 data_port = 0;
148 return s.getInputStream();
149 }
150 } catch (Exception e) {
151 e.printStackTrace();
152 }
153 return null;
154 }
155
156 /**
157 * Handles the protocol exchange with the client.
158 */
159
160 public void run() {
161 boolean done = false;
162 String str;
163 int res;
164 boolean logged = false;
165 boolean waitpass = false;
166
167 try {
168 in = new BufferedReader(new InputStreamReader(
169 client.getInputStream()));
170 out = new PrintWriter(client.getOutputStream(), true);
171 out.println("220 tatooine FTP server (SunOS 5.8) ready.");
172 } catch (Exception ex) {
173 return;
174 }
175 while (!done) {
176 try {
177 str = in.readLine();
178 res = parseCmd(str);
179 if ((res > PASS && res != QUIT) && !logged) {
180 out.println("530 Not logged in.");
181 continue;
182 }
183 switch (res) {
184 case ERROR:
185 out.println("500 '" + str +
186 "': command not understood.");
187 break;
188 case USER:
189 if (!logged && !waitpass) {
190 out.println("331 Password required for " + arg);
191 waitpass = true;
192 } else {
193 out.println("503 Bad sequence of commands.");
194 }
195 break;
196 case PASS:
197 if (!logged && waitpass) {
198 out.println("230-Welcome to the FTP server!");
199 out.println("ab");
200 out.println("230 Guest login ok, " +
201 "access restrictions apply.");
202 logged = true;
203 waitpass = false;
204 } else
205 out.println("503 Bad sequence of commands.");
206 break;
207 case QUIT:
208 out.println("221 Goodbye.");
209 out.flush();
210 out.close();
211 if (pasv != null)
212 pasv.close();
213 done = true;
214 break;
215 case TYPE:
216 out.println("200 Type set to " + arg + ".");
217 break;
218 case CWD:
219 out.println("250 CWD command successful.");
220 break;
221 case EPSV:
222 if (!extendedEnabled || !pasvEnabled) {
223 out.println("500 EPSV is disabled, " +
224 "use PORT instead.");
225 continue;
226 }
227 if ("all".equalsIgnoreCase(arg)) {
228 out.println("200 EPSV ALL command successful.");
229 continue;
230 }
231 try {
232 if (pasv == null)
233 pasv = new ServerSocket(0);
234 int port = pasv.getLocalPort();
235 out.println("229 Entering Extended" +
236 " Passive Mode (|||" + port + "|)");
237 } catch (IOException ssex) {
238 out.println("425 Can't build data connection:" +
239 " Connection refused.");
240 }
241 break;
242
243 case PASV:
244 if (!pasvEnabled) {
245 out.println("500 PASV is disabled, " +
246 "use PORT instead.");
247 continue;
248 }
249 try {
250 if (pasv == null)
251 pasv = new ServerSocket(0);
252 int port = pasv.getLocalPort();
253
254 // Parenthesis are optional, so let's be
255 // nasty and don't put them
256 out.println("227 Entering Passive Mode" +
257 " 127,0,0,1," +
258 (port >> 8) + "," + (port & 0xff));
259 } catch (IOException ssex) {
260 out.println("425 Can't build data connection:" +
261 "Connection refused.");
262 }
263 break;
264 case PORT:
265 if (!portEnabled) {
266 out.println("500 PORT is disabled, " +
267 "use PASV instead");
268 continue;
269 }
270 StringBuffer host;
271 int i = 0, j = 4;
272 while (j > 0) {
273 i = arg.indexOf(',', i + 1);
274 if (i < 0)
275 break;
276 j--;
277 }
278 if (j != 0) {
279 out.println("500 '" + arg + "':" +
280 " command not understood.");
281 continue;
282 }
283 try {
284 host = new StringBuffer(arg.substring(0, i));
285 for (j = 0; j < host.length(); j++)
286 if (host.charAt(j) == ',')
287 host.setCharAt(j, '.');
288 String ports = arg.substring(i+1);
289 i = ports.indexOf(',');
290 data_port = Integer.parseInt(
291 ports.substring(0, i)) << 8;
292 data_port += (Integer.parseInt(
293 ports.substring(i+1)));
294 data_addr = InetAddress.getByName(
295 host.toString());
296 out.println("200 Command okay.");
297 } catch (Exception ex3) {
298 data_port = 0;
299 data_addr = null;
300 out.println("500 '" + arg + "':" +
301 " command not understood.");
302 }
303 break;
304 case RETR:
305 {
306 File file = new File(arg);
307 if (!file.exists()) {
308 System.out.println("File not found");
309 out.println("200 Command okay.");
310 out.println("550 '" + arg +
311 "' No such file or directory.");
312 break;
313 }
314 FileInputStream fin = new FileInputStream(file);
315 OutputStream dout = getOutDataStream();
316 if (dout != null) {
317 out.println("150 Binary data connection" +
318 " for " + arg +
319 " (" + client.getInetAddress().
320 getHostAddress() + ") (" +
321 file.length() + " bytes).");
322 int c;
323 int len = 0;
324 while ((c = fin.read()) != -1) {
325 dout.write(c);
326 len++;
327 }
328 dout.flush();
329 dout.close();
330 fin.close();
331 out.println("226 Binary Transfer complete.");
332 } else {
333 out.println("425 Can't build data" +
334 " connection: Connection refused.");
335 }
336 }
337 break;
338 }
339 } catch (IOException ioe) {
340 ioe.printStackTrace();
341 try {
342 out.close();
343 } catch (Exception ex2) {
344 }
345 done = true;
346 }
347 }
348 }
349 }
350
351 public FtpServer(int port) {
352 this.port = port;
353 }
354
355 public FtpServer() {
356 this(21);
357 }
358
359 public int getPort() {
360 if (server != null)
361 return server.getLocalPort();
362 return 0;
363 }
364
365 /**
366 * A way to tell the server that it can stop.
367 */
368 synchronized public void terminate() {
369 done = true;
370 }
371
372
373 /*
374 * All we got to do here is create a ServerSocket and wait for a
375 * connection. When a connection happens, we just have to create
376 * a thread that will handle it.
377 */
378 public void run() {
379 try {
380 server = new ServerSocket(port);
381 Socket client;
382 client = server.accept();
383 (new FtpServerHandler(client)).start();
384 server.close();
385 } catch (Exception e) {
386 }
387 }
388 }
389
390 public static void main(String[] args) throws Exception {
391 MarkResetTest test = new MarkResetTest();
392 }
393
394 public MarkResetTest() {
395 FtpServer server = null;
396 try {
397 server = new FtpServer(0);
398 server.start();
399 int port = 0;
400 while (port == 0) {
401 Thread.sleep(500);
402 port = server.getPort();
403 }
404
405 String filename = "EncDec.doc";
406 URL url = new URL("ftp://localhost:" + port + "/" +
407 filename);
408
409 URLConnection con = url.openConnection();
410 System.out.println("getContent: " + con.getContent());
411 System.out.println("getContent-length: " + con.getContentLength());
412
413 InputStream is = con.getInputStream();
414
415 /**
416 * guessContentTypeFromStream method calls mark and reset methods
417 * on the given stream. Make sure that calling
418 * guessContentTypeFromStream repeatedly does not affect
419 * reading from the stream afterwards
420 */
421 System.out.println("Call GuessContentTypeFromStream()" +
422 " several times..");
423 for (int i = 0; i < 5; i++) {
424 System.out.println((i + 1) + " mime-type: " +
425 con.guessContentTypeFromStream(is));
426 }
427
428 int len = 0;
429 int c;
430 while ((c = is.read()) != -1) {
431 len++;
432 }
433 is.close();
434 System.out.println("read: " + len + " bytes of the file");
435
436 // We're done!
437 server.terminate();
438 server.interrupt();
439
440 // Did we pass ?
441 if (len != (new File(filename)).length()) {
442 throw new Exception("Failed to read the file correctly");
443 }
444 System.out.println("PASSED: File read correctly");
445 } catch (Exception e) {
446 e.printStackTrace();
447 try {
448 server.terminate();
449 server.interrupt();
450 } catch (Exception ex) {
451 }
452 throw new RuntimeException("FTP support error: " + e.getMessage());
453 }
454 }
455}