// ========================================================================
// Copyright (c) 2004-2009 Mort Bay Consulting Pty. Ltd.
// ------------------------------------------------------------------------
// All rights reserved. This program and the accompanying materials
// are made available under the terms of the Eclipse Public License v1.0
// and Apache License v2.0 which accompanies this distribution.
// The Eclipse Public License is available at
// http://www.eclipse.org/legal/epl-v10.html
// The Apache License v2.0 is available at
// http://www.opensource.org/licenses/apache2.0.php
// You may elect to redistribute this code under either of these licenses.
// ========================================================================
package org.eclipse.jetty.server;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;
import static org.junit.Assert.fail;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.LineNumberReader;
import java.io.PrintWriter;
import java.net.Socket;
import java.util.Enumeration;
import java.util.Locale;
import java.util.Map;
import javax.servlet.ServletContext;
import javax.servlet.ServletException;
import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSessionContext;
import org.eclipse.jetty.http.Generator;
import org.eclipse.jetty.http.HttpHeaders;
import org.eclipse.jetty.http.HttpURI;
import org.eclipse.jetty.http.Parser;
import org.eclipse.jetty.io.ByteArrayBuffer;
import org.eclipse.jetty.io.ByteArrayEndPoint;
import org.eclipse.jetty.io.Connection;
import org.eclipse.jetty.io.EndPoint;
import org.eclipse.jetty.server.bio.SocketConnector;
import org.eclipse.jetty.server.handler.AbstractHandler;
import org.eclipse.jetty.server.handler.ContextHandler;
import org.eclipse.jetty.server.session.AbstractSession;
import org.eclipse.jetty.server.session.AbstractSessionManager;
import org.eclipse.jetty.server.session.HashSessionIdManager;
import org.eclipse.jetty.server.session.HashSessionManager;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
/**
*
*/
public class ResponseTest
{
private Server server;
private LocalConnector connector;
@Before
public void init() throws Exception
{
server = new Server();
connector = new LocalConnector();
server.addConnector(connector);
server.setHandler(new DumpHandler());
server.start();
}
@After
public void destroy() throws Exception
{
server.stop();
server.join();
}
@Test
public void testContentType() throws Exception
{
AbstractHttpConnection connection = new TestHttpConnection(connector,new ByteArrayEndPoint(), connector.getServer());
Response response = connection.getResponse();
assertEquals(null,response.getContentType());
response.setHeader("Content-Type","text/something");
assertEquals("text/something",response.getContentType());
response.setContentType("foo/bar");
assertEquals("foo/bar",response.getContentType());
response.getWriter();
assertEquals("foo/bar;charset=ISO-8859-1",response.getContentType());
response.setContentType("foo2/bar2");
assertEquals("foo2/bar2;charset=ISO-8859-1",response.getContentType());
response.setHeader("name","foo");
Enumeration<?> en=response.getHeaders("name");
assertEquals("foo",en.nextElement());
assertFalse(en.hasMoreElements());
response.addHeader("name","bar");
en=response.getHeaders("name");
assertEquals("foo",en.nextElement());
assertEquals("bar",en.nextElement());
assertFalse(en.hasMoreElements());
response.recycle();
response.setContentType("text/html");
assertEquals("text/html",response.getContentType());
response.getWriter();
assertEquals("text/html;charset=ISO-8859-1",response.getContentType());
response.setContentType("foo2/bar2");
assertEquals("foo2/bar2;charset=ISO-8859-1",response.getContentType());
response.recycle();
response.setContentType("text/xml;charset=ISO-8859-7");
response.getWriter();
response.setContentType("text/html;charset=UTF-8");
assertEquals("text/html;charset=ISO-8859-7",response.getContentType());
response.recycle();
response.setContentType("text/html;charset=US-ASCII");
response.getWriter();
assertEquals("text/html;charset=US-ASCII",response.getContentType());
response.recycle();
response.setContentType("text/json");
response.getWriter();
assertEquals("text/json;charset=UTF-8", response.getContentType());
}
@Test
public void testLocale() throws Exception
{
AbstractHttpConnection connection = new TestHttpConnection(connector,new ByteArrayEndPoint(), connector.getServer());
Request request = connection.getRequest();
Response response = connection.getResponse();
ContextHandler context = new ContextHandler();
context.addLocaleEncoding(Locale.ENGLISH.toString(),"ISO-8859-1");
context.addLocaleEncoding(Locale.ITALIAN.toString(),"ISO-8859-2");
request.setContext(context.getServletContext());
response.setLocale(java.util.Locale.ITALIAN);
assertEquals(null,response.getContentType());
response.setContentType("text/plain");
assertEquals("text/plain;charset=ISO-8859-2",response.getContentType());
response.recycle();
response.setContentType("text/plain");
response.setCharacterEncoding("utf-8");
response.setLocale(java.util.Locale.ITALIAN);
assertEquals("text/plain;charset=UTF-8",response.getContentType());
assertTrue(response.toString().indexOf("charset=UTF-8")>0);
}
@Test
public void testContentTypeCharacterEncoding() throws Exception
{
AbstractHttpConnection connection = new TestHttpConnection(connector,new ByteArrayEndPoint(), connector.getServer());
Response response = connection.getResponse();
response.setContentType("foo/bar");
response.setCharacterEncoding("utf-8");
assertEquals("foo/bar;charset=utf-8",response.getContentType());
response.getWriter();
assertEquals("foo/bar;charset=utf-8",response.getContentType());
response.setContentType("foo2/bar2");
assertEquals("foo2/bar2;charset=utf-8",response.getContentType());
response.setCharacterEncoding("ISO-8859-1");
assertEquals("foo2/bar2;charset=utf-8",response.getContentType());
response.recycle();
response.setContentType("text/html");
response.setCharacterEncoding("utf-8");
assertEquals("text/html;charset=UTF-8",response.getContentType());
response.getWriter();
assertEquals("text/html;charset=UTF-8",response.getContentType());
response.setContentType("text/xml");
assertEquals("text/xml;charset=UTF-8",response.getContentType());
response.setCharacterEncoding("ISO-8859-1");
assertEquals("text/xml;charset=UTF-8",response.getContentType());
}
@Test
public void testCharacterEncodingContentType() throws Exception
{
Response response = new Response(new TestHttpConnection(connector,new ByteArrayEndPoint(), connector.getServer()));
response.setCharacterEncoding("utf-8");
response.setContentType("foo/bar");
assertEquals("foo/bar;charset=utf-8",response.getContentType());
response.getWriter();
assertEquals("foo/bar;charset=utf-8",response.getContentType());
response.setContentType("foo2/bar2");
assertEquals("foo2/bar2;charset=utf-8",response.getContentType());
response.setCharacterEncoding("ISO-8859-1");
assertEquals("foo2/bar2;charset=utf-8",response.getContentType());
response.recycle();
response.setCharacterEncoding("utf-8");
response.setContentType("text/html");
assertEquals("text/html;charset=UTF-8",response.getContentType());
response.getWriter();
assertEquals("text/html;charset=UTF-8",response.getContentType());
response.setContentType("text/xml");
assertEquals("text/xml;charset=UTF-8",response.getContentType());
response.setCharacterEncoding("iso-8859-1");
assertEquals("text/xml;charset=UTF-8",response.getContentType());
}
@Test
public void testContentTypeWithCharacterEncoding() throws Exception
{
Response response = new Response(new TestHttpConnection(connector,new ByteArrayEndPoint(), connector.getServer()));
response.setCharacterEncoding("utf16");
response.setContentType("foo/bar; charset=utf-8");
assertEquals("foo/bar; charset=utf-8",response.getContentType());
response.getWriter();
assertEquals("foo/bar; charset=utf-8",response.getContentType());
response.setContentType("foo2/bar2");
assertEquals("foo2/bar2;charset=utf-8",response.getContentType());
response.setCharacterEncoding("ISO-8859-1");
assertEquals("foo2/bar2;charset=utf-8",response.getContentType());
response.recycle();
response.setCharacterEncoding("utf16");
response.setContentType("text/html; charset=utf-8");
assertEquals("text/html;charset=UTF-8",response.getContentType());
response.getWriter();
assertEquals("text/html;charset=UTF-8",response.getContentType());
response.setContentType("text/xml");
assertEquals("text/xml;charset=UTF-8",response.getContentType());
response.setCharacterEncoding("iso-8859-1");
assertEquals("text/xml;charset=UTF-8",response.getContentType());
}
@Test
public void testContentTypeWithOther() throws Exception
{
Response response = new Response(new TestHttpConnection(connector,new ByteArrayEndPoint(), connector.getServer()));
response.setContentType("foo/bar; other=xyz");
assertEquals("foo/bar; other=xyz",response.getContentType());
response.getWriter();
assertEquals("foo/bar; other=xyz;charset=ISO-8859-1",response.getContentType());
response.setContentType("foo2/bar2");
assertEquals("foo2/bar2;charset=ISO-8859-1",response.getContentType());
response.recycle();
response.setCharacterEncoding("utf-8");
response.setContentType("text/html; other=xyz");
assertEquals("text/html; other=xyz;charset=utf-8",response.getContentType());
response.getWriter();
assertEquals("text/html; other=xyz;charset=utf-8",response.getContentType());
response.setContentType("text/xml");
assertEquals("text/xml;charset=UTF-8",response.getContentType());
}
@Test
public void testContentTypeWithCharacterEncodingAndOther() throws Exception
{
Response response = new Response(new TestHttpConnection(connector,new ByteArrayEndPoint(), connector.getServer()));
response.setCharacterEncoding("utf16");
response.setContentType("foo/bar; charset=utf-8 other=xyz");
assertEquals("foo/bar; charset=utf-8 other=xyz",response.getContentType());
response.getWriter();
assertEquals("foo/bar; charset=utf-8 other=xyz",response.getContentType());
response.recycle();
response.setCharacterEncoding("utf16");
response.setContentType("text/html; other=xyz charset=utf-8");
assertEquals("text/html; other=xyz charset=utf-8",response.getContentType());
response.getWriter();
assertEquals("text/html; other=xyz charset=utf-8",response.getContentType());
response.recycle();
response.setCharacterEncoding("utf16");
response.setContentType("foo/bar; other=pq charset=utf-8 other=xyz");
assertEquals("foo/bar; other=pq charset=utf-8 other=xyz",response.getContentType());
response.getWriter();
assertEquals("foo/bar; other=pq charset=utf-8 other=xyz",response.getContentType());
}
@Test
public void testStatusCodes() throws Exception
{
Response response=newResponse();
response.sendError(404);
assertEquals(404, response.getStatus());
assertEquals(null, response.getReason());
response=newResponse();
response.sendError(500, "Database Error");
assertEquals(500, response.getStatus());
assertEquals("Database Error", response.getReason());
assertEquals("must-revalidate,no-cache,no-store", response.getHeader(HttpHeaders.CACHE_CONTROL));
response=newResponse();
response.setStatus(200);
assertEquals(200, response.getStatus());
assertEquals(null, response.getReason());
response=newResponse();
response.sendError(406, "Super Nanny");
assertEquals(406, response.getStatus());
assertEquals("Super Nanny", response.getReason());
assertEquals("must-revalidate,no-cache,no-store", response.getHeader(HttpHeaders.CACHE_CONTROL));
}
@Test
public void testEncodeRedirect()
throws Exception
{
AbstractHttpConnection connection=new TestHttpConnection(connector,new ByteArrayEndPoint(), connector.getServer());
Response response = new Response(connection);
Request request = connection.getRequest();
request.setServerName("myhost");
request.setServerPort(8888);
request.setContextPath("/path");
assertEquals("http://myhost:8888/path/info;param?query=0&more=1#target",response.encodeURL("http://myhost:8888/path/info;param?query=0&more=1#target"));
request.setRequestedSessionId("12345");
request.setRequestedSessionIdFromCookie(false);
AbstractSessionManager manager=new HashSessionManager();
manager.setSessionIdManager(new HashSessionIdManager());
request.setSessionManager(manager);
request.setSession(new TestSession(manager,"12345"));
manager.setCheckingRemoteSessionIdEncoding(false);
assertEquals("http://myhost:8888/path/info;param;jsessionid=12345?query=0&more=1#target",response.encodeURL("http://myhost:8888/path/info;param?query=0&more=1#target"));
assertEquals("http://other:8888/path/info;param;jsessionid=12345?query=0&more=1#target",response.encodeURL("http://other:8888/path/info;param?query=0&more=1#target"));
assertEquals("http://myhost/path/info;param;jsessionid=12345?query=0&more=1#target",response.encodeURL("http://myhost/path/info;param?query=0&more=1#target"));
assertEquals("http://myhost:8888/other/info;param;jsessionid=12345?query=0&more=1#target",response.encodeURL("http://myhost:8888/other/info;param?query=0&more=1#target"));
manager.setCheckingRemoteSessionIdEncoding(true);
assertEquals("http://myhost:8888/path/info;param;jsessionid=12345?query=0&more=1#target",response.encodeURL("http://myhost:8888/path/info;param?query=0&more=1#target"));
assertEquals("http://other:8888/path/info;param?query=0&more=1#target",response.encodeURL("http://other:8888/path/info;param?query=0&more=1#target"));
assertEquals("http://myhost/path/info;param?query=0&more=1#target",response.encodeURL("http://myhost/path/info;param?query=0&more=1#target"));
assertEquals("http://myhost:8888/other/info;param?query=0&more=1#target",response.encodeURL("http://myhost:8888/other/info;param?query=0&more=1#target"));
request.setContextPath("");
assertEquals("http://myhost:8888/;jsessionid=12345",response.encodeURL("http://myhost:8888"));
assertEquals("https://myhost:8888/;jsessionid=12345",response.encodeURL("https://myhost:8888"));
assertEquals("mailto:/foo", response.encodeURL("mailto:/foo"));
assertEquals("http://myhost:8888/;jsessionid=12345",response.encodeURL("http://myhost:8888/"));
assertEquals("http://myhost:8888/;jsessionid=12345", response.encodeURL("http://myhost:8888/;jsessionid=7777"));
assertEquals("http://myhost:8888/;param;jsessionid=12345?query=0&more=1#target",response.encodeURL("http://myhost:8888/;param?query=0&more=1#target"));
assertEquals("http://other:8888/path/info;param?query=0&more=1#target",response.encodeURL("http://other:8888/path/info;param?query=0&more=1#target"));
manager.setCheckingRemoteSessionIdEncoding(false);
assertEquals("/foo;jsessionid=12345", response.encodeURL("/foo"));
assertEquals("/;jsessionid=12345", response.encodeURL("/"));
assertEquals("/foo.html;jsessionid=12345#target", response.encodeURL("/foo.html#target"));
assertEquals(";jsessionid=12345", response.encodeURL(""));
}
@Test
public void testSendRedirect()
throws Exception
{
String[][] tests={
{"/other/location?name=value","http://myhost:8888/other/location;jsessionid=12345?name=value"},
{"/other/location","http://myhost:8888/other/location"},
{"/other/l%20cation","http://myhost:8888/other/l%20cation"},
{"location","http://myhost:8888/path/location"},
{"./location","http://myhost:8888/path/location"},
{"../location","http://myhost:8888/location"},
{"/other/l%20cation","http://myhost:8888/other/l%20cation"},
{"l%20cation","http://myhost:8888/path/l%20cation"},
{"./l%20cation","http://myhost:8888/path/l%20cation"},
{"../l%20cation","http://myhost:8888/l%20cation"},
};
for (int i=1;i<tests.length;i++)
{
ByteArrayEndPoint out=new ByteArrayEndPoint(new byte[]{},4096);
AbstractHttpConnection connection=new TestHttpConnection(connector,out, connector.getServer());
Response response = new Response(connection);
Request request = connection.getRequest();
request.setServerName("myhost");
request.setServerPort(8888);
request.setUri(new HttpURI("/path/info;param;jsessionid=12345?query=0&more=1#target"));
request.setContextPath("/path");
request.setRequestedSessionId("12345");
request.setRequestedSessionIdFromCookie(i>0);
AbstractSessionManager manager=new HashSessionManager();
manager.setSessionIdManager(new HashSessionIdManager());
request.setSessionManager(manager);
request.setSession(new TestSession(manager,"12345"));
manager.setCheckingRemoteSessionIdEncoding(false);
response.sendRedirect(tests[i][0]);
String location = out.getOut().toString();
int l=location.indexOf("Location: ");
int e=location.indexOf('\n',l);
location=location.substring(l+10,e).trim();
assertEquals(tests[i][0],tests[i][1],location);
}
}
@Test
public void testSetBufferSize () throws Exception
{
Response response = new Response(new TestHttpConnection(connector,new ByteArrayEndPoint(), connector.getServer()));
response.setBufferSize(20*1024);
response.getWriter().print("hello");
try
{
response.setBufferSize(21*1024);
fail("Expected IllegalStateException on Request.setBufferSize");
}
catch (Exception e)
{
assertTrue(e instanceof IllegalStateException);
}
}
@Test
public void testZeroContent () throws Exception
{
Response response = new Response (new TestHttpConnection(connector, new ByteArrayEndPoint(), connector.getServer()));
PrintWriter writer = response.getWriter();
response.setContentLength(0);
assertTrue(!response.isCommitted());
assertTrue(!writer.checkError());
writer.print("");
assertTrue(!writer.checkError());
assertTrue(response.isCommitted());
}
@Test
public void testHead() throws Exception
{
Server server = new Server();
try
{
SocketConnector socketConnector = new SocketConnector();
socketConnector.setPort(0);
server.addConnector(socketConnector);
server.setHandler(new AbstractHandler()
{
public void handle(String string, Request baseRequest, HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException
{
response.setStatus(200);
response.setContentType("text/plain");
PrintWriter w = response.getWriter();
w.flush();
w.println("Geht");
w.flush();
w.println("Doch");
((Request) request).setHandled(true);
}
});
server.start();
Socket socket = new Socket("localhost",socketConnector.getLocalPort());
socket.getOutputStream().write("HEAD / HTTP/1.1\r\nHost: localhost\r\n\r\n".getBytes());
socket.getOutputStream().write("GET / HTTP/1.1\r\nHost: localhost\r\nConnection: close\r\n\r\n".getBytes());
socket.getOutputStream().flush();
LineNumberReader reader = new LineNumberReader(new InputStreamReader(socket.getInputStream()));
String line = reader.readLine();
while (line!=null && line.length()>0)
line = reader.readLine();
while (line!=null && line.length()==0)
line = reader.readLine();
assertTrue(line!=null && line.startsWith("HTTP/1.1 200 OK"));
}
finally
{
server.stop();
}
}
@Test
public void testAddCookie() throws Exception
{
Response response = new Response(new TestHttpConnection(connector,new ByteArrayEndPoint(), connector.getServer()));
Cookie cookie=new Cookie("name","value");
cookie.setDomain("domain");
cookie.setPath("/path");
cookie.setSecure(true);
cookie.setComment("comment__HTTP_ONLY__");
response.addCookie(cookie);
String set = response.getHttpFields().getStringField("Set-Cookie");
assertEquals("name=value;Path=/path;Domain=domain;Secure;HttpOnly",set);
}
private Response newResponse()
{
ByteArrayEndPoint endPoint = new ByteArrayEndPoint();
endPoint.setOut(new ByteArrayBuffer(1024));
endPoint.setGrowOutput(true);
AbstractHttpConnection connection=new TestHttpConnection(connector, endPoint, connector.getServer());
connection.getGenerator().reset();
AbstractHttpConnection.setCurrentConnection(connection);
Response response = connection.getResponse();
connection.getRequest().setRequestURI("/test");
return response;
}
private class TestSession extends AbstractSession
{
public TestSession(AbstractSessionManager abstractSessionManager, String id)
{
super(abstractSessionManager, System.currentTimeMillis(),System.currentTimeMillis(), id);
}
public Object getAttribute(String name)
{
return null;
}
public Enumeration getAttributeNames()
{
return null;
}
public long getCreationTime()
{
return 0;
}
public String getId()
{
return "12345";
}
public long getLastAccessedTime()
{
return 0;
}
public int getMaxInactiveInterval()
{
return 0;
}
public ServletContext getServletContext()
{
return null;
}
public HttpSessionContext getSessionContext()
{
return null;
}
public Object getValue(String name)
{
return null;
}
public String[] getValueNames()
{
return null;
}
public void invalidate()
{
}
public boolean isNew()
{
return false;
}
public void putValue(String name, Object value)
{
}
public void removeAttribute(String name)
{
}
public void removeValue(String name)
{
}
public void setAttribute(String name, Object value)
{
}
public void setMaxInactiveInterval(int interval)
{
}
protected Map newAttributeMap()
{
return null;
}
}
static class TestHttpConnection extends AbstractHttpConnection
{
public TestHttpConnection(Connector connector, EndPoint endpoint, Server server)
{
super(connector,endpoint,server);
}
public TestHttpConnection(Connector connector, EndPoint endpoint, Server server, Parser parser, Generator generator, Request request)
{
super(connector,endpoint,server,parser,generator,request);
}
@Override
public Connection handle() throws IOException
{
return this;
}
}
}