001: package org.mortbay.jetty;
002:
003: import java.io.BufferedReader;
004: import java.io.IOException;
005: import java.io.InputStream;
006: import java.io.InputStreamReader;
007: import java.io.OutputStream;
008: import java.io.PrintWriter;
009: import java.io.Writer;
010: import java.net.Socket;
011: import java.net.URL;
012: import java.net.URLConnection;
013: import java.util.Arrays;
014: import java.util.Random;
015:
016: import javax.servlet.ServletException;
017: import javax.servlet.http.HttpServletRequest;
018: import javax.servlet.http.HttpServletResponse;
019:
020: import junit.framework.TestCase;
021:
022: import org.mortbay.jetty.handler.AbstractHandler;
023: import org.mortbay.util.IO;
024:
025: /**
026: * HttpServer Tester.
027: */
028: public class HttpServerTestBase extends TestCase {
029:
030: // ~ Static fields/initializers
031: // ---------------------------------------------
032:
033: /** The request. */
034: private static final String REQUEST1_HEADER = "POST / HTTP/1.0\n"
035: + "Host: localhost\n"
036: + "Content-Type: text/xml; charset=utf-8\n"
037: + "Connection: close\n" + "Content-Length: ";
038: private static final String REQUEST1_CONTENT = "<?xml version=\"1.0\" encoding=\"ISO-8859-1\"?>\n"
039: + "<nimbus xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n"
040: + " xsi:noNamespaceSchemaLocation=\"nimbus.xsd\" version=\"1.0\">\n"
041: + "</nimbus>";
042: private static final String REQUEST1 = REQUEST1_HEADER
043: + REQUEST1_CONTENT.getBytes().length + "\n\n"
044: + REQUEST1_CONTENT;
045:
046: /** The expected response. */
047: private static final String RESPONSE1 = "HTTP/1.1 200 OK\n"
048: + "Connection: close\n" + "Server: Jetty(6.1.x)\n" + "\n"
049: + "Hello world\n";
050:
051: // Break the request up into three pieces, splitting the header.
052: private static final String FRAGMENT1 = REQUEST1.substring(0, 16);
053: private static final String FRAGMENT2 = REQUEST1.substring(16, 34);
054: private static final String FRAGMENT3 = REQUEST1.substring(34);
055:
056: /** Second test request. */
057: private static final String REQUEST2_HEADER = "POST / HTTP/1.0\n"
058: + "Host: localhost\n" + "Content-Type: text/xml\n"
059: + "Content-Length: ";
060:
061: private static final String REQUEST2_CONTENT = "<?xml version=\"1.0\" encoding=\"ISO-8859-1\"?>\n"
062: + "<nimbus xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n"
063: + " xsi:noNamespaceSchemaLocation=\"nimbus.xsd\" version=\"1.0\">\n"
064: + " <request requestId=\"1\">\n"
065: + " <getJobDetails>\n"
066: + " <jobId>73</jobId>\n"
067: + " </getJobDetails>\n"
068: + " </request>\n"
069: + "</nimbus>";
070:
071: private static final String REQUEST2 = REQUEST2_HEADER
072: + REQUEST2_CONTENT.getBytes().length + "\n\n"
073: + REQUEST2_CONTENT;
074:
075: private static final String RESPONSE2_CONTENT = "<?xml version=\"1.0\" encoding=\"ISO-8859-1\"?>\n"
076: + "<nimbus xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n"
077: + " xsi:noNamespaceSchemaLocation=\"nimbus.xsd\" version=\"1.0\">\n"
078: + " <request requestId=\"1\">\n"
079: + " <getJobDetails>\n"
080: + " <jobId>73</jobId>\n"
081: + " </getJobDetails>\n"
082: + " </request>\n"
083: + "</nimbus>\n";
084: private static final String RESPONSE2 = "HTTP/1.1 200 OK\n"
085: + "Content-Length: " + RESPONSE2_CONTENT.getBytes().length
086: + "\n" + "Server: Jetty(6.1.x)\n" + "\n"
087: + RESPONSE2_CONTENT;
088:
089: // Useful constants
090: private static final long PAUSE = 5L;
091: private static final int LOOPS = 20;
092: private static final String HOST = "localhost";
093:
094: private Connector _connector;
095: private int port = 0;
096:
097: protected void tearDown() throws Exception {
098: super .tearDown();
099: Thread.sleep(250);
100: }
101:
102: // ~ Methods
103: // ----------------------------------------------------------------
104:
105: /**
106: * Feed the server the entire request at once.
107: *
108: * @throws Exception
109: * @throws InterruptedException
110: */
111: public void testRequest1_jetty() throws Exception,
112: InterruptedException {
113: Server server = startServer(new HelloWorldHandler());
114: Socket client = new Socket(HOST, port);
115: OutputStream os = client.getOutputStream();
116:
117: os.write(REQUEST1.getBytes());
118: os.flush();
119:
120: // Read the response.
121: String response = readResponse(client);
122:
123: // Shut down
124: client.close();
125: server.stop();
126:
127: // Check the response
128: assertEquals("response", RESPONSE1, response);
129: }
130:
131: /* --------------------------------------------------------------- */
132: public void testFragmentedChunk() throws Exception {
133:
134: Server server = startServer(new EchoHandler());
135: Socket client = new Socket(HOST, port);
136: OutputStream os = client.getOutputStream();
137:
138: os.write(("GET /R2 HTTP/1.1\015\012"
139: + "Host: localhost\015\012"
140: + "Transfer-Encoding: chunked\015\012"
141: + "Content-Type: text/plain\015\012"
142: + "Connection: close\015\012" + "\015\012").getBytes());
143: os.flush();
144: Thread.sleep(PAUSE);
145: os.write(("5\015\012").getBytes());
146: os.flush();
147: Thread.sleep(PAUSE);
148: os.write(("ABCDE\015\012" + "0;\015\012\015\012").getBytes());
149: os.flush();
150:
151: // Read the response.
152: String response = readResponse(client);
153:
154: // Shut down
155: client.close();
156: server.stop();
157:
158: assertTrue(true); // nothing checked yet.
159:
160: }
161:
162: /**
163: * Feed the server fragmentary headers and see how it copes with it.
164: *
165: * @throws Exception
166: * @throws InterruptedException
167: */
168: public void testRequest1Fragments_jetty() throws Exception,
169: InterruptedException {
170: Server server = startServer(new HelloWorldHandler());
171: String response;
172:
173: try {
174: Socket client = new Socket(HOST, port);
175: OutputStream os = client.getOutputStream();
176:
177: // Write a fragment, flush, sleep, write the next fragment, etc.
178: os.write(FRAGMENT1.getBytes());
179: os.flush();
180: Thread.sleep(PAUSE);
181: os.write(FRAGMENT2.getBytes());
182: os.flush();
183: Thread.sleep(PAUSE);
184: os.write(FRAGMENT3.getBytes());
185: os.flush();
186:
187: // Read the response
188: response = readResponse(client);
189:
190: // Shut down
191: client.close();
192: } finally {
193: server.stop();
194: }
195:
196: // Check the response
197: assertEquals("response", RESPONSE1, response);
198: }
199:
200: public void testRequest2_jetty() throws Exception {
201: byte[] bytes = REQUEST2.getBytes();
202: Server server = startServer(new EchoHandler());
203:
204: try {
205: for (int i = 0; i < LOOPS; i++) {
206: Socket client = new Socket(HOST, port);
207: OutputStream os = client.getOutputStream();
208:
209: os.write(bytes);
210: os.flush();
211:
212: // Read the response
213: String response = readResponse(client);
214: client.close();
215:
216: // Check the response
217: assertEquals("response " + i, RESPONSE2, response);
218: }
219: } finally {
220: // Shut down
221: server.stop();
222: }
223: }
224:
225: /**
226: * @throws Exception
227: */
228: public void testRequest2Fragments_jetty() throws Exception {
229: Random random = new Random(System.currentTimeMillis());
230: byte[] bytes = REQUEST2.getBytes();
231: final int pointCount = 2;
232: Server server = startServer(new EchoHandler());
233:
234: try {
235:
236: for (int i = 0; i < LOOPS; i++) {
237:
238: int[] points = new int[pointCount];
239: StringBuffer message = new StringBuffer();
240:
241: message.append("iteration #" + (i + 1));
242:
243: // Pick fragment points at random
244: for (int j = 0; j < points.length; ++j) {
245: points[j] = random.nextInt(bytes.length);
246: }
247:
248: // Sort the list
249: Arrays.sort(points);
250:
251: Socket client = new Socket(HOST, port);
252: OutputStream os = client.getOutputStream();
253:
254: writeFragments(bytes, points, message, os);
255:
256: // Read the response
257: String response = readResponse(client);
258:
259: // Close the client
260: client.close();
261:
262: // Check the response
263: assertEquals("response for " + i + " "
264: + message.toString(), RESPONSE2, response);
265: }
266: } finally {
267: // Shut down
268: server.stop();
269: }
270: }
271:
272: public void testRequest2Iterate_jetty() throws Exception {
273: byte[] bytes = REQUEST2.getBytes();
274: Server server = startServer(new EchoHandler());
275:
276: try {
277: for (int i = 0; i < bytes.length; i += 3) {
278: int[] points = new int[] { i };
279: StringBuffer message = new StringBuffer();
280:
281: message.append("iteration #" + (i + 1));
282:
283: // Sort the list
284: Arrays.sort(points);
285:
286: Socket client = new Socket(HOST, port);
287: OutputStream os = client.getOutputStream();
288:
289: writeFragments(bytes, points, message, os);
290:
291: // Read the response
292: String response = readResponse(client);
293:
294: // Close the client
295: client.close();
296:
297: // Check the response
298: assertEquals("response for " + i + " "
299: + message.toString(), RESPONSE2, response);
300: }
301: } finally {
302: // Shut down
303: server.stop();
304: }
305: }
306:
307: /**
308: * After several iterations, I generated some known bad fragment points.
309: *
310: * @throws Exception
311: */
312: public void testRequest2KnownBad_jetty() throws Exception {
313: byte[] bytes = REQUEST2.getBytes();
314: int[][] badPoints = new int[][] { { 70 }, // beginning here, drops last line of request
315: { 71 }, // no response at all
316: { 72 }, // again starts drops last line of request
317: { 74 }, // again, no response at all
318: };
319: Server server = startServer(new EchoHandler());
320:
321: try {
322: for (int i = 0; i < badPoints.length; ++i) {
323: Socket client = new Socket(HOST, port);
324: OutputStream os = client.getOutputStream();
325: StringBuffer message = new StringBuffer();
326:
327: message.append("iteration #" + (i + 1));
328: writeFragments(bytes, badPoints[i], message, os);
329:
330: // Read the response
331: String response = readResponse(client);
332:
333: // Close the client
334: client.close();
335:
336: // Check the response
337: // TODO - change to equals when code gets fixed
338: assertNotSame("response for " + message.toString(),
339: RESPONSE2, response);
340: }
341: } finally {
342: // Shut down
343: server.stop();
344: }
345: }
346:
347: /**
348: * After several iterations, I generated some known bad fragment points.
349: *
350: * @throws Exception
351: */
352: public void testFlush() throws Exception {
353: Server server = startServer(new DataHandler());
354: try {
355: String[] encoding = { "NONE", "UTF-8", "ISO-8859-1",
356: "ISO-8859-2", "JIS" };
357:
358: for (int e = 0; e < encoding.length; e++) {
359: for (int b = 1; b < 100; b += 50) {
360: for (int w = 1024; w < 10000; w += 4096) {
361: for (int c = 0; c < 2; c++) {
362: String test = encoding[e] + "x" + b + "x"
363: + w + "x" + "x" + c;
364: URL url = new URL(
365: "http://"
366: + HOST
367: + ":"
368: + port
369: + "/?writes="
370: + w
371: + "&block="
372: + b
373: + (e == 0 ? ""
374: : ("&encoding=" + encoding[e]))
375: + (c == 0 ? "&chars=true"
376: : ""));
377: InputStream in = (InputStream) url
378: .getContent();
379: String response = IO.toString(in);
380:
381: assertEquals(test, b * w, response.length());
382: }
383: }
384: }
385: }
386:
387: } finally {
388: // Shut down
389: server.stop();
390: Thread.yield();
391: }
392:
393: }
394:
395: /**
396: * Read entire response from the client. Close the output.
397: *
398: * @param client
399: * Open client socket.
400: *
401: * @return The response string.
402: *
403: * @throws IOException
404: */
405: private static String readResponse(Socket client)
406: throws IOException {
407: BufferedReader br = null;
408:
409: try {
410: br = new BufferedReader(new InputStreamReader(client
411: .getInputStream()));
412:
413: StringBuffer sb = new StringBuffer();
414: String line;
415:
416: while ((line = br.readLine()) != null) {
417: sb.append(line);
418: sb.append('\n');
419: }
420:
421: return sb.toString();
422: } finally {
423: if (br != null) {
424: br.close();
425: }
426: }
427: }
428:
429: protected HttpServerTestBase(Connector connector) {
430: _connector = connector;
431: }
432:
433: /**
434: * Create the server.
435: *
436: * @param handler
437: *
438: * @return Newly created server, ready to start.
439: *
440: * @throws Exception
441: */
442: private Server startServer(Handler handler) throws Exception {
443: Server server = new Server();
444:
445: _connector.setPort(0);
446: server.setConnectors(new Connector[] { _connector });
447: server.setHandler(handler);
448: server.start();
449: port = _connector.getLocalPort();
450: return server;
451: }
452:
453: private void writeFragments(byte[] bytes, int[] points,
454: StringBuffer message, OutputStream os) throws IOException,
455: InterruptedException {
456: int last = 0;
457:
458: // Write out the fragments
459: for (int j = 0; j < points.length; ++j) {
460: int point = points[j];
461:
462: os.write(bytes, last, point - last);
463: last = point;
464: os.flush();
465: Thread.sleep(PAUSE);
466:
467: // Update the log message
468: message.append(" point #" + (j + 1) + ": " + point);
469: }
470:
471: // Write the last fragment
472: os.write(bytes, last, bytes.length - last);
473: os.flush();
474: Thread.sleep(PAUSE);
475: }
476:
477: // ~ Inner Classes
478: // ----------------------------------------------------------
479: private static class EchoHandler extends AbstractHandler {
480:
481: // ~ Methods
482: // ------------------------------------------------------------
483: public void handle(String target, HttpServletRequest request,
484: HttpServletResponse response, int dispatch)
485: throws IOException, ServletException {
486:
487: Request base_request = (request instanceof Request) ? (Request) request
488: : HttpConnection.getCurrentConnection()
489: .getRequest();
490: base_request.setHandled(true);
491:
492: PrintWriter writer = response.getWriter();
493: BufferedReader reader = request.getReader();
494: int count = 0;
495: String line;
496:
497: while ((line = reader.readLine()) != null) {
498: writer.print(line);
499: writer.print('\n');
500: count += line.length();
501: }
502:
503: if (count == 0)
504: throw new IllegalStateException("no input recieved");
505: }
506: }
507:
508: // ----------------------------------------------------------
509: private static class HelloWorldHandler extends AbstractHandler {
510: // ------------------------------------------------------------
511: public void handle(String target, HttpServletRequest request,
512: HttpServletResponse response, int dispatch)
513: throws IOException, ServletException {
514: Request base_request = (request instanceof Request) ? (Request) request
515: : HttpConnection.getCurrentConnection()
516: .getRequest();
517: base_request.setHandled(true);
518: response.setStatus(200);
519: response.getOutputStream().print("Hello world");
520: }
521: }
522:
523: // ----------------------------------------------------------
524: private static class DataHandler extends AbstractHandler {
525: // ------------------------------------------------------------
526: public void handle(String target, HttpServletRequest request,
527: HttpServletResponse response, int dispatch)
528: throws IOException, ServletException {
529: Request base_request = (request instanceof Request) ? (Request) request
530: : HttpConnection.getCurrentConnection()
531: .getRequest();
532: base_request.setHandled(true);
533: response.setStatus(200);
534:
535: String tmp = request.getParameter("writes");
536: int writes = Integer.parseInt(tmp == null ? "10" : tmp);
537: tmp = request.getParameter("block");
538: int block = Integer.parseInt(tmp == null ? "10" : tmp);
539: String encoding = request.getParameter("encoding");
540: String chars = request.getParameter("chars");
541:
542: String chunk = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz"
543: .substring(0, block);
544: response.setContentType("text/plain");
545: if (encoding == null) {
546: byte[] bytes = chunk.getBytes("ISO-8859-1");
547: OutputStream out = response.getOutputStream();
548: for (int i = 0; i < writes; i++)
549: out.write(bytes);
550: } else if ("true".equals(chars)) {
551: response.setCharacterEncoding(encoding);
552: Writer out = response.getWriter();
553: char[] c = chunk.toCharArray();
554: for (int i = 0; i < writes; i++)
555: out.write(c);
556: } else {
557: response.setCharacterEncoding(encoding);
558: Writer out = response.getWriter();
559: for (int i = 0; i < writes; i++)
560: out.write(chunk);
561: }
562: }
563: }
564:
565: }
|