001: // Copyright (C) 2003,2004,2005 by Object Mentor, Inc. All rights reserved.
002: // Released under the terms of the GNU General Public License version 2 or later.
003: package fitnesse.http;
004:
005: import junit.framework.TestCase;
006: import java.io.PipedInputStream;
007: import java.io.PipedOutputStream;
008: import fitnesse.components.Base64;
009: import fitnesse.util.FileUtil;
010: import fitnesse.wiki.WikiPage;
011:
012: public class RequestTest extends TestCase {
013: PipedOutputStream output;
014:
015: Request request;
016:
017: public Thread parseThread;
018:
019: public Exception exception;
020:
021: public void setUp() throws Exception {
022: output = new PipedOutputStream();
023: request = new Request(new PipedInputStream(output));
024: }
025:
026: public void tearDown() throws Exception {
027: output.close();
028: }
029:
030: private void writeToPipe(String value) throws Exception {
031: byte[] bytes = value.getBytes();
032: output.write(bytes);
033: }
034:
035: public void testMultilevelRequest() throws Exception {
036: startParsing();
037: writeToPipe("GET /SomePage.SubPage?edit HTTP/1.1\r\n");
038: writeToPipe("\r\n");
039: finishParsing();
040: assertEquals("SomePage.SubPage", request.getResource());
041: }
042:
043: public void testSimpleRequest() throws Exception {
044: assertFalse(request.hasBeenParsed());
045: startParsing();
046: writeToPipe("GET /request-uri HTTP/1.1\r\n");
047: writeToPipe("\r\n");
048: finishParsing();
049: assertTrue(request.hasBeenParsed());
050: assertEquals("/request-uri", request.getRequestUri());
051: }
052:
053: public void testMalformedRequestLine() throws Exception {
054: startParsing();
055: writeToPipe("/resource HTTP/1.1\r\n");
056: writeToPipe("\r\n");
057: finishParsing();
058: assertNotNull("no exception was thrown", exception);
059: assertEquals(
060: "The request string is malformed and can not be parsed",
061: exception.getMessage());
062: }
063:
064: public void testBadMethod() throws Exception {
065: startParsing();
066: writeToPipe("DELETE /resource HTTP/1.1\r\n");
067: writeToPipe("\r\n");
068: finishParsing();
069: assertNotNull("no exception was thrown", exception);
070: assertEquals("The DELETE method is not currently supported",
071: exception.getMessage());
072: }
073:
074: public void testQueryStringValueWithNoQueryString()
075: throws Exception {
076: startParsing();
077: writeToPipe("GET /resource HTTP/1.1\r\n");
078: writeToPipe("\r\n");
079: finishParsing();
080: assertEquals("", request.getQueryString());
081: }
082:
083: public void testParsingRequestUri() throws Exception {
084: startParsing();
085: writeToPipe("GET /resource?queryString HTTP/1.1\r\n");
086: writeToPipe("\r\n");
087: finishParsing();
088: assertEquals("resource", request.getResource());
089: assertEquals("queryString", request.getQueryString());
090: }
091:
092: public void testCanGetQueryStringValues() throws Exception {
093: startParsing();
094: writeToPipe("GET /resource?key1=value1&key2=value2 HTTP/1.1\r\n");
095: writeToPipe("\r\n");
096: finishParsing();
097: checkInputs();
098: }
099:
100: public void testHeaders() throws Exception {
101: startParsing();
102: writeToPipe("GET /something HTTP/1.1\r\n");
103: writeToPipe("Content-Length: 0\r\n");
104: writeToPipe("Accept: text/html\r\n");
105: writeToPipe("Connection: Keep-Alive\r\n");
106: writeToPipe("\r\n");
107: finishParsing();
108: assertEquals(true, request.hasHeader("Content-Length"));
109: assertEquals("0", request.getHeader("Content-Length"));
110: assertEquals(true, request.hasHeader("Accept"));
111: assertEquals("text/html", request.getHeader("Accept"));
112: assertEquals(true, request.hasHeader("Connection"));
113: assertEquals("Keep-Alive", request.getHeader("Connection"));
114: assertEquals(false, request.hasHeader("Something-Else"));
115: assertEquals(null, request.getHeader("Something-Else"));
116: }
117:
118: public void testEntityBodyWithoutContentLength() throws Exception {
119: startParsing();
120: writeToPipe("GET /something HTTP/1.1\r\n");
121: writeToPipe("\r\n");
122: writeToPipe("This is the Entity Body");
123: finishParsing();
124: assertEquals("", request.getBody());
125: }
126:
127: public void testEntityBodyIsRead() throws Exception {
128: startParsing();
129: writeToPipe("GET /something HTTP/1.1\r\n");
130: writeToPipe("Content-Length: 23\r\n");
131: writeToPipe("\r\n");
132: writeToPipe("This is the Entity Body");
133: finishParsing();
134: assertEquals("This is the Entity Body", request.getBody());
135: }
136:
137: public void testEntityBodyParametersAreParsed() throws Exception {
138: startParsing();
139: writeToPipe("GET /something HTTP/1.1\r\n");
140: writeToPipe("Content-Length: 23\r\n");
141: writeToPipe("\r\n");
142: writeToPipe("key1=value1&key2=value2");
143: finishParsing();
144: checkInputs();
145: }
146:
147: private void checkInputs() {
148: assertEquals(true, request.hasInput("key1"));
149: assertEquals("value1", request.getInput("key1"));
150: assertEquals(true, request.hasInput("key2"));
151: assertEquals("value2", request.getInput("key2"));
152: assertEquals(false, request.hasInput("someOtherKey"));
153: assertEquals(null, request.getInput("someOtherKey"));
154: }
155:
156: public void testPostMethod() throws Exception {
157: startParsing();
158: writeToPipe("POST /something HTTP/1.1\r\n");
159: writeToPipe("\r\n");
160: finishParsing();
161: assertNull("POST method should be allowed", exception);
162: }
163:
164: public void testSimpleInputStyle() throws Exception {
165: startParsing();
166: writeToPipe("GET /abc?something HTTP/1.1\r\n");
167: writeToPipe("\r\n");
168: finishParsing();
169: assertEquals(true, request.hasInput("something"));
170: }
171:
172: public void testOperaPostRequest() throws Exception {
173: startParsing();
174: writeToPipe("POST /HelloThere HTTP/1.1\r\n");
175: writeToPipe("User-Agent: Mozilla/4.0 (compatible; MSIE 6.0; MSIE 5.5; Windows NT 5.1) Opera 7.02 [en]\r\n");
176: writeToPipe("Host: localhost:75\r\n");
177: writeToPipe("Accept: text/html, image/png, image/jpeg, image/gif, image/x-xbitmap, */*;q=0.1\r\n");
178: writeToPipe("Accept-Language: en\r\n");
179: writeToPipe("Accept-Charset: windows-1252, utf-8, utf-16, iso-8859-1;q=0.6, *;q=0.1\r\n");
180: writeToPipe("Accept-Encoding: deflate, gzip, x-gzip, identity, *;q=0\r\n");
181: writeToPipe("Referer: http://localhost:75/HeloThere?edit=\r\n");
182: writeToPipe("Connection: Keep-Alive, TE\r\n");
183: writeToPipe("TE: deflate, gzip, chunked, identity, trailers\r\n");
184: writeToPipe("Content-type: application/x-www-form-urlencoded\r\n");
185: writeToPipe("Content-length: 67\r\n");
186: writeToPipe("\r\n");
187: writeToPipe("saveId=1046584670887&Edit=on&Search=on&Test=on&Suite=on&content=abc");
188:
189: finishParsing();
190:
191: assertTrue(request.hasInput("saveId"));
192: assertTrue(request.hasInput(WikiPage.ACTION_EDIT));
193: assertTrue(request.hasInput(WikiPage.ACTION_SEARCH));
194: assertTrue(request.hasInput(WikiPage.ACTION_TEST));
195: assertTrue(request.hasInput(WikiPage.ACTION_SUITE));
196: assertTrue(request.hasInput("content"));
197: }
198:
199: public void testBigPosts() throws Exception {
200: StringBuffer buffer = new StringBuffer();
201: for (int i = 0; i < 10; i++) {
202: for (int j = 0; j < 1000; j++)
203: buffer.append(i);
204: }
205:
206: startParsing();
207: writeToPipe("POST /HelloThere HTTP/1.1\r\n");
208: writeToPipe("Content-length: 10021\r\n");
209: writeToPipe("\r\n");
210: writeToPipe("saveId=12345&content=");
211: writeToPipe(buffer.toString());
212:
213: finishParsing();
214: assertEquals(buffer.toString(), request.getInput("content"));
215: }
216:
217: public void testMultiPartForms() throws Exception {
218: String content = "----bob\r\n"
219: + "Content-Disposition: form-data; name=\"key1\"\r\n"
220: + "\r\n" + "value1\r\n" + "----bob\r\n"
221: + "Content-Disposition: form-data; name=\"key3\"\r\n"
222: + "\r\n" + "some\r\nmulti-line\r\nvalue\r\n\r\n"
223: + "----bob\r\n"
224: + "Content-Disposition: form-data; name=\"key2\"\r\n"
225: + "\r\n" + "value2\r\n" + "----bob\r\n"
226: + "Content-Disposition: form-data; name=\"key4\"\r\n"
227: + "\r\n" + "\r\n" + "----bob--\r\n";
228:
229: startParsing();
230: writeToPipe("GET /request-uri HTTP/1.1\r\n");
231: writeToPipe("Content-Length: " + content.length() + "\r\n");
232: writeToPipe("Content-Type: multipart/form-data; boundary=--bob\r\n");
233: writeToPipe("\r\n");
234: writeToPipe(content);
235: finishParsing();
236:
237: if (exception != null) {
238: throw exception;
239: }
240: checkInputs();
241: assertEquals(true, request.hasInput("key3"));
242: assertEquals("some\r\nmulti-line\r\nvalue\r\n", request
243: .getInput("key3"));
244:
245: assertEquals(true, request.hasInput("key4"));
246: assertEquals("", request.getInput("key4"));
247: }
248:
249: public void testUploadingFile() throws Exception {
250: String content = "----bob\r\n"
251: + "Content-Disposition: form-data; name=\"file1\"; filename=\"mike dile.txt\"\r\n"
252: + "Content-Type: text/plain\r\n" + "\r\n"
253: + "file contents\r\n" + "----bob--\r\n";
254:
255: startParsing();
256: writeToPipe("GET /request-uri HTTP/1.1\r\n");
257: writeToPipe("Content-Length: " + content.length() + "\r\n");
258: writeToPipe("Content-Type: multipart/form-data; boundary=--bob\r\n");
259: writeToPipe("\r\n");
260: writeToPipe(content);
261: finishParsing();
262:
263: testUploadedFile("file1", "mike dile.txt", "text/plain",
264: "file contents");
265: }
266:
267: public void testUploadingTwoFiles() throws Exception {
268: String content = "-----------------------------7d32df3a80058\r\n"
269: + "Content-Disposition: form-data; name=\"file\"; filename=\"C:\\test.txt\"\r\n"
270: + "Content-Type: text/plain\r\n"
271: + "\r\n"
272: + "test\r\n"
273: + "-----------------------------7d32df3a80058\r\n"
274: + "Content-Disposition: form-data; name=\"file2\"; filename=\"C:\\test2.txt\"\r\n"
275: + "Content-Type: text/plain\r\n"
276: + "\r\n"
277: + "test2\r\n"
278: + "-----------------------------7d32df3a80058--\r\n";
279:
280: startParsing();
281: writeToPipe("GET /request-uri HTTP/1.1\r\n");
282: writeToPipe("Content-Length: " + content.length() + "\r\n");
283: writeToPipe("Content-Type: multipart/form-data; boundary=---------------------------7d32df3a80058\r\n");
284: writeToPipe("\r\n");
285: writeToPipe(content);
286: finishParsing();
287:
288: testUploadedFile("file", "C:\\test.txt", "text/plain", "test");
289: testUploadedFile("file2", "C:\\test2.txt", "text/plain",
290: "test2");
291: }
292:
293: private void testUploadedFile(String name, String filename,
294: String contentType, String content) throws Exception {
295: assertEquals(true, request.hasInput(name));
296: UploadedFile file = (UploadedFile) request.getInput(name);
297: assertNotNull(file);
298: assertEquals(filename, file.getName());
299: assertEquals(contentType, file.getType());
300: assertEquals(content, new String(FileUtil.getFileContent(file
301: .getFile())));
302: }
303:
304: public void testUploadingBinaryFile() throws Exception {
305: startParsing();
306: writeToPipe("GET /request-uri HTTP/1.1\r\n");
307: writeToPipe("Content-Length: " + (83) + "\r\n");
308: writeToPipe("Content-Type: multipart/form-data; boundary=--bob\r\n");
309: writeToPipe("\r\n");
310:
311: writeToPipe("----bob\r\n");
312: writeToPipe("Content-Disposition: name=\"n\"; filename=\"f\"\r\n");
313: writeToPipe("\r\n");
314: output
315: .write(new byte[] { (byte) 0x9D, (byte) 0x90,
316: (byte) 0x81 });
317: output.write("file contents".getBytes());
318: writeToPipe("\r\n");
319:
320: writeToPipe("----bob--");
321: finishParsing();
322:
323: UploadedFile file = (UploadedFile) request.getInput("n");
324: assertNotNull(file);
325:
326: byte[] contents = FileUtil.getFileBytes(file.getFile());
327: assertEquals((byte) 0x9D, contents[0]);
328: assertEquals((byte) 0x90, contents[1]);
329: assertEquals((byte) 0x81, contents[2]);
330: assertEquals("file contents", new String(contents, 3,
331: contents.length - 3));
332: }
333:
334: public void testCanGetCredentials() throws Exception {
335: startParsing();
336: writeToPipe("GET /abc?something HTTP/1.1\r\n");
337: writeToPipe("Authorization: Basic QWxhZGRpbjpvcGVuIHNlc2FtZQ==\r\n");
338: writeToPipe("\r\n");
339: finishParsing();
340: request.getCredentials();
341: assertEquals("Aladdin", request.getAuthorizationUsername());
342: assertEquals("open sesame", request.getAuthorizationPassword());
343: }
344:
345: public void testDoenstChokeOnMissingPassword() throws Exception {
346: startParsing();
347: writeToPipe("GET /abc?something HTTP/1.1\r\n");
348: writeToPipe("Authorization: Basic " + Base64.encode("Aladin")
349: + "\r\n");
350: writeToPipe("\r\n");
351: finishParsing();
352: try {
353: request.getCredentials();
354: } catch (Exception e) {
355: fail("Exception: " + e.getMessage());
356: }
357: }
358:
359: public void testGetUserpass() throws Exception {
360: assertEquals("Aladdin:open sesame", request
361: .getUserpass("Basic QWxhZGRpbjpvcGVuIHNlc2FtZQ=="));
362: }
363:
364: public void testUnicodeCharacters() throws Exception {
365: startParsing();
366: writeToPipe("GET /?key=%EB%AA%80%EB%AA%81%EB%AA%82%EB%AA%83 HTTP/1.1\r\n\r\n");
367: finishParsing();
368: assertEquals("\uba80\uba81\uba82\uba83", request
369: .getInput("key"));
370: }
371:
372: public void testParsingProgress() throws Exception {
373: startParsing();
374: writeToPipe("GET /something HTTP/1.1\r\n");
375: output.flush();
376: Thread.sleep(20);
377: assertEquals(25, request.numberOfBytesParsed());
378: writeToPipe("Content-Length: 23\r\n");
379: output.flush();
380: Thread.sleep(20);
381: assertEquals(45, request.numberOfBytesParsed());
382: writeToPipe("\r\n");
383: writeToPipe("This is ");
384: output.flush();
385: Thread.sleep(20);
386: assertEquals(55, request.numberOfBytesParsed());
387: writeToPipe("the Entity Body");
388: output.flush();
389: Thread.sleep(20);
390: assertEquals(70, request.numberOfBytesParsed());
391: finishParsing();
392: }
393:
394: private void startParsing() {
395: parseThread = new Thread() {
396: public synchronized void run() {
397: try {
398: request.parse();
399: } catch (Exception e) {
400: exception = e;
401: }
402: }
403: };
404: parseThread.start();
405: }
406:
407: private void finishParsing() throws Exception {
408: parseThread.join();
409: }
410: }
|