Author: hlship
Date: Mon Mar 12 19:08:27 2007
New Revision: 517491
URL: http://svn.apache.org/viewvc?view=rev&rev=517491
Log:
TAPESTRY-1282: Assets should be streamed with an appropriate content type, even
when the container is unable to provide the content type
Added:
tapestry/tapestry5/tapestry-core/trunk/src/test/java/org/apache/tapestry/internal/services/ResourceStreamerImplTest.java
tapestry/tapestry5/tapestry-core/trunk/src/test/resources/org/apache/tapestry/internal/services/test.css
tapestry/tapestry5/tapestry-core/trunk/src/test/resources/org/apache/tapestry/internal/services/test.js
Modified:
tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/services/InternalModule.java
tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/services/ResourceStreamerImpl.java
tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/test/TapestryTestCase.java
Modified:
tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/services/InternalModule.java
URL:
http://svn.apache.org/viewvc/tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/services/InternalModule.java?view=diff&rev=517491&r1=517490&r2=517491
==============================================================================
---
tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/services/InternalModule.java
(original)
+++
tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/services/InternalModule.java
Mon Mar 12 19:08:27 2007
@@ -474,9 +474,23 @@
return _chainBuilder.build(BindingFactory.class, configuration);
}
- public ResourceStreamer buildResourceStreamer()
+ /**
+ * The configuration for the ResourceStreamer maps file extensions (i.e.,
"css") to content
+ * types (i.e., "text/css"). This is used when the servlet container does
not provide a useful
+ * content type.
+ */
+ public ResourceStreamer buildResourceStreamer(Map<String, String>
configuration)
{
- return new ResourceStreamerImpl(_response);
+ return new ResourceStreamerImpl(_response, configuration);
+ }
+
+ /**
+ * Adds content types for "css" and "js" file extensions.
+ */
+ public void contributeResourceStreamer(MappedConfiguration<String, String>
configuration)
+ {
+ configuration.add("css", "text/css");
+ configuration.add("js", "text/javascript");
}
public SessionHolder buildSessionHolder()
Modified:
tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/services/ResourceStreamerImpl.java
URL:
http://svn.apache.org/viewvc/tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/services/ResourceStreamerImpl.java?view=diff&rev=517491&r1=517490&r2=517491
==============================================================================
---
tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/services/ResourceStreamerImpl.java
(original)
+++
tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/internal/services/ResourceStreamerImpl.java
Mon Mar 12 19:08:27 2007
@@ -20,6 +20,7 @@
import java.io.OutputStream;
import java.net.URL;
import java.net.URLConnection;
+import java.util.Map;
import org.apache.tapestry.internal.TapestryInternalUtils;
import org.apache.tapestry.ioc.Resource;
@@ -29,15 +30,18 @@
{
private final Response _response;
+ private final Map<String, String> _configuration;
+
private final int _bufferSize = 1000;
// One year, in milliseconds
final static long EXPIRE_DELTA = 31536000000l;
- public ResourceStreamerImpl(final Response response)
+ public ResourceStreamerImpl(final Response response, Map<String, String>
configuration)
{
_response = response;
+ _configuration = configuration;
}
public void streamResource(Resource resource) throws IOException
@@ -48,8 +52,7 @@
int contentLength = connection.getContentLength();
- if (contentLength >= 0)
- _response.setContentLength(contentLength);
+ if (contentLength >= 0) _response.setContentLength(contentLength);
// Could get this from the ResourceCache, but can't imagine
// it's very expensive.
@@ -61,10 +64,22 @@
String contentType = connection.getContentType();
+ if ("content/unknown".equals(contentType)) contentType = null;
+
if (contentType == null)
- contentType = "application/octet-stream";
+ {
+ String file = resource.getFile();
+ int dotx = file.lastIndexOf('.');
+
+ if (dotx > 0)
+ {
+ String extension = file.substring(dotx + 1);
+
+ contentType = _configuration.get(extension);
+ }
- // TODO: if content type is null
+ if (contentType == null) contentType = "application/octet-stream";
+ }
InputStream is = null;
@@ -82,8 +97,7 @@
{
int length = is.read(buffer);
- if (length < 0)
- break;
+ if (length < 0) break;
os.write(buffer, 0, length);
}
Modified:
tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/test/TapestryTestCase.java
URL:
http://svn.apache.org/viewvc/tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/test/TapestryTestCase.java?view=diff&rev=517491&r1=517490&r2=517491
==============================================================================
---
tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/test/TapestryTestCase.java
(original)
+++
tapestry/tapestry5/tapestry-core/trunk/src/main/java/org/apache/tapestry/test/TapestryTestCase.java
Mon Mar 12 19:08:27 2007
@@ -29,7 +29,9 @@
import java.util.List;
import java.util.Locale;
+import javax.servlet.ServletOutputStream;
import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
import org.apache.tapestry.AnnotationProvider;
@@ -333,6 +335,40 @@
expect(request.getSession(create)).andReturn(session);
}
+ protected final HttpServletResponse newHttpServletResponse()
+ {
+ return newMock(HttpServletResponse.class);
+ }
+
+ protected final void train_setContentLength(HttpServletResponse response,
int length)
+ {
+ response.setContentLength(length);
+ }
+
+ protected final void train_setDateHeader(HttpServletResponse response,
String headerName,
+ long date)
+ {
+ response.setDateHeader(headerName, date);
+ }
+
+ protected final void train_setContentType(HttpServletResponse response,
String contentType)
+ {
+ response.setContentType(contentType);
+ }
+
+ protected final void train_getOutputStream(HttpServletResponse response,
+ ServletOutputStream stream)
+ {
+ try
+ {
+ expect(response.getOutputStream()).andReturn(stream);
+ }
+ catch (IOException e)
+ {
+ fail(e.getMessage(), e);
+ }
+ }
+
protected final HttpSession newHttpSession()
{
return newMock(HttpSession.class);
Added:
tapestry/tapestry5/tapestry-core/trunk/src/test/java/org/apache/tapestry/internal/services/ResourceStreamerImplTest.java
URL:
http://svn.apache.org/viewvc/tapestry/tapestry5/tapestry-core/trunk/src/test/java/org/apache/tapestry/internal/services/ResourceStreamerImplTest.java?view=auto&rev=517491
==============================================================================
---
tapestry/tapestry5/tapestry-core/trunk/src/test/java/org/apache/tapestry/internal/services/ResourceStreamerImplTest.java
(added)
+++
tapestry/tapestry5/tapestry-core/trunk/src/test/java/org/apache/tapestry/internal/services/ResourceStreamerImplTest.java
Mon Mar 12 19:08:27 2007
@@ -0,0 +1,94 @@
+// Copyright 2007 The Apache Software Foundation
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package org.apache.tapestry.internal.services;
+
+import static org.easymock.EasyMock.anyInt;
+import static org.easymock.EasyMock.anyLong;
+import static org.easymock.EasyMock.eq;
+
+import java.io.IOException;
+
+import javax.servlet.ServletOutputStream;
+import javax.servlet.http.HttpServletResponse;
+
+import org.apache.tapestry.internal.test.InternalBaseTestCase;
+import org.apache.tapestry.ioc.Resource;
+import org.apache.tapestry.ioc.internal.util.ClasspathResource;
+import org.apache.tapestry.services.Request;
+import org.apache.tapestry.services.RequestGlobals;
+import org.apache.tapestry.services.Response;
+import org.testng.annotations.Test;
+
+/**
+ * Tests for the [EMAIL PROTECTED] ResourceStreamerImpl} class.
+ */
+public class ResourceStreamerImplTest extends InternalBaseTestCase
+{
+ @Test
+ public void content_type_css() throws IOException
+ {
+ content_type("text/css", "test.css");
+ }
+
+ @Test
+ public void content_type_js() throws IOException
+ {
+ content_type("text/javascript", "test.js");
+ }
+
+ @Test
+ public void content_type_gif() throws IOException
+ {
+ content_type("image/gif", "test.gif");
+ }
+
+ private void content_type(String contentType, String fileName) throws
IOException
+ {
+ Request request = newRequest();
+ HttpServletResponse hsr = newHttpServletResponse();
+
+ train_setContentLength(hsr, anyInt());
+ train_setDateHeader(hsr, eq("Last-Modified"), anyLong());
+ train_setDateHeader(hsr, eq("Expires"), anyLong());
+ train_setContentType(hsr, contentType);
+ train_getOutputStream(hsr, new TestServletOutputStream());
+
+ replay();
+
+ Response response = new ResponseImpl(hsr);
+ ResourceStreamer streamer = getService(ResourceStreamer.class);
+ RequestGlobals globals = getService(RequestGlobals.class);
+
+ globals.store(request, response);
+
+ String path = getClass().getPackage().getName().replace('.', '/') +
"/" + fileName;
+
+ Resource resource = new ClasspathResource(path);
+
+ streamer.streamResource(resource);
+
+ verify();
+ }
+
+ private static class TestServletOutputStream extends ServletOutputStream
+ {
+ @Override
+ public void write(int b) throws IOException
+ {
+ // Empty.
+ }
+ }
+
+}
Added:
tapestry/tapestry5/tapestry-core/trunk/src/test/resources/org/apache/tapestry/internal/services/test.css
URL:
http://svn.apache.org/viewvc/tapestry/tapestry5/tapestry-core/trunk/src/test/resources/org/apache/tapestry/internal/services/test.css?view=auto&rev=517491
==============================================================================
---
tapestry/tapestry5/tapestry-core/trunk/src/test/resources/org/apache/tapestry/internal/services/test.css
(added)
+++
tapestry/tapestry5/tapestry-core/trunk/src/test/resources/org/apache/tapestry/internal/services/test.css
Mon Mar 12 19:08:27 2007
@@ -0,0 +1,4 @@
+body {
+ margin: 0;
+ padding: 0;
+}
Added:
tapestry/tapestry5/tapestry-core/trunk/src/test/resources/org/apache/tapestry/internal/services/test.js
URL:
http://svn.apache.org/viewvc/tapestry/tapestry5/tapestry-core/trunk/src/test/resources/org/apache/tapestry/internal/services/test.js?view=auto&rev=517491
==============================================================================
---
tapestry/tapestry5/tapestry-core/trunk/src/test/resources/org/apache/tapestry/internal/services/test.js
(added)
+++
tapestry/tapestry5/tapestry-core/trunk/src/test/resources/org/apache/tapestry/internal/services/test.js
Mon Mar 12 19:08:27 2007
@@ -0,0 +1 @@
+var x = 5;