From 70d761ab3aeba06a3acfd0a8bccdde49a5d8b9b4 Mon Sep 17 00:00:00 2001 From: =?utf8?q?David=20=E2=80=98Bombe=E2=80=99=20Roden?= Date: Mon, 27 Jul 2015 20:13:47 +0200 Subject: [PATCH] Deliver static files from filesystem --- .../net/pterodactylus/sone/main/DebugLoaders.java | 8 ++ .../pterodactylus/sone/main/DefaultLoaders.java | 8 ++ .../java/net/pterodactylus/sone/main/Loaders.java | 4 + .../net/pterodactylus/sone/web/ReloadingPage.java | 88 ++++++++++++++++++++++ .../net/pterodactylus/sone/web/WebInterface.java | 7 +- .../pterodactylus/sone/main/DebugLoadersTest.java | 35 ++++++++- .../sone/main/DefaultLoadersTest.java | 29 +++++++ template.txt | 1 + 8 files changed, 172 insertions(+), 8 deletions(-) create mode 100644 src/main/java/net/pterodactylus/sone/web/ReloadingPage.java create mode 100644 template.txt diff --git a/src/main/java/net/pterodactylus/sone/main/DebugLoaders.java b/src/main/java/net/pterodactylus/sone/main/DebugLoaders.java index 1daa18a..14c58b6 100644 --- a/src/main/java/net/pterodactylus/sone/main/DebugLoaders.java +++ b/src/main/java/net/pterodactylus/sone/main/DebugLoaders.java @@ -3,7 +3,10 @@ package net.pterodactylus.sone.main; import java.io.File; import net.pterodactylus.sone.template.FilesystemTemplate; +import net.pterodactylus.sone.web.ReloadingPage; import net.pterodactylus.util.template.Template; +import net.pterodactylus.util.web.Page; +import net.pterodactylus.util.web.Request; /** * {@link Loaders} implementation that loads all resources from the filesystem. @@ -23,4 +26,9 @@ public class DebugLoaders implements Loaders { return new FilesystemTemplate(new File(filesystemPath, path).getAbsolutePath()); } + @Override + public Page loadStaticPage(String basePath, String prefix, String mimeType) { + return new ReloadingPage(basePath, new File(filesystemPath, prefix).getAbsolutePath(), mimeType); + } + } diff --git a/src/main/java/net/pterodactylus/sone/main/DefaultLoaders.java b/src/main/java/net/pterodactylus/sone/main/DefaultLoaders.java index 39a289d..4978d7c 100644 --- a/src/main/java/net/pterodactylus/sone/main/DefaultLoaders.java +++ b/src/main/java/net/pterodactylus/sone/main/DefaultLoaders.java @@ -9,6 +9,9 @@ import java.io.UnsupportedEncodingException; import net.pterodactylus.util.io.Closer; import net.pterodactylus.util.template.Template; +import net.pterodactylus.util.web.Page; +import net.pterodactylus.util.web.Request; +import net.pterodactylus.util.web.StaticPage; /** * Default {@link Loaders} implementation that loads resources from the classpath. @@ -33,4 +36,9 @@ public class DefaultLoaders implements Loaders { } } + @Override + public Page loadStaticPage(String pathPrefix, String basePath, String mimeType) { + return new StaticPage(pathPrefix, basePath, mimeType); + } + } diff --git a/src/main/java/net/pterodactylus/sone/main/Loaders.java b/src/main/java/net/pterodactylus/sone/main/Loaders.java index 73f8ec6..35ae81f 100644 --- a/src/main/java/net/pterodactylus/sone/main/Loaders.java +++ b/src/main/java/net/pterodactylus/sone/main/Loaders.java @@ -1,6 +1,9 @@ package net.pterodactylus.sone.main; import net.pterodactylus.util.template.Template; +import net.pterodactylus.util.web.Page; +import net.pterodactylus.util.web.Request; +import net.pterodactylus.util.web.StaticPage; import com.google.inject.ImplementedBy; @@ -13,5 +16,6 @@ import com.google.inject.ImplementedBy; public interface Loaders { Template loadTemplate(String path); + Page loadStaticPage(String basePath, String prefix, String mimeType); } diff --git a/src/main/java/net/pterodactylus/sone/web/ReloadingPage.java b/src/main/java/net/pterodactylus/sone/web/ReloadingPage.java new file mode 100644 index 0000000..0c8f516 --- /dev/null +++ b/src/main/java/net/pterodactylus/sone/web/ReloadingPage.java @@ -0,0 +1,88 @@ +/* + * Sone - ReloadingPage.java - Copyright © 2010–2015 David Roden + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package net.pterodactylus.sone.web; + +import java.io.File; +import java.io.FileInputStream; +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; + +import net.pterodactylus.util.io.Closer; +import net.pterodactylus.util.io.StreamCopier; +import net.pterodactylus.util.web.Page; +import net.pterodactylus.util.web.Request; +import net.pterodactylus.util.web.Response; + +/** + * {@link Page} implementation that delivers static files from the filesystem. + * + * @param + * The type of the request + * @author David ‘Bombe’ Roden + */ +public class ReloadingPage implements Page { + + private final String pathPrefix; + private final String filesystemPath; + private final String mimeType; + + public ReloadingPage(String pathPrefix, String filesystemPathPrefix, String mimeType) { + this.pathPrefix = pathPrefix; + this.filesystemPath = filesystemPathPrefix; + this.mimeType = mimeType; + } + + /** + * {@inheritDoc} + */ + @Override + public String getPath() { + return pathPrefix; + } + + /** + * {@inheritDoc} + */ + @Override + public boolean isPrefixPage() { + return true; + } + + /** + * {@inheritDoc} + */ + @Override + public Response handleRequest(REQ request, Response response) throws IOException { + String path = request.getUri().getPath(); + int lastSlash = path.lastIndexOf('/'); + String filename = path.substring(lastSlash + 1); + InputStream fileInputStream = new FileInputStream(new File(filesystemPath, filename)); + if (fileInputStream == null) { + return response.setStatusCode(404).setStatusText("Not found."); + } + OutputStream contentOutputStream = response.getContent(); + try { + StreamCopier.copy(fileInputStream, contentOutputStream); + } finally { + Closer.close(fileInputStream); + Closer.close(contentOutputStream); + } + return response.setStatusCode(200).setStatusText("OK").setContentType(mimeType); + } +} diff --git a/src/main/java/net/pterodactylus/sone/web/WebInterface.java b/src/main/java/net/pterodactylus/sone/web/WebInterface.java index a3f3352..f524e5f 100644 --- a/src/main/java/net/pterodactylus/sone/web/WebInterface.java +++ b/src/main/java/net/pterodactylus/sone/web/WebInterface.java @@ -146,7 +146,6 @@ import net.pterodactylus.util.template.TemplateContextFactory; import net.pterodactylus.util.template.TemplateProvider; import net.pterodactylus.util.template.XmlFilter; import net.pterodactylus.util.web.RedirectPage; -import net.pterodactylus.util.web.StaticPage; import net.pterodactylus.util.web.TemplatePage; import com.google.common.collect.Collections2; @@ -685,9 +684,9 @@ public class WebInterface { pageToadlets.add(pageToadletFactory.createPageToadlet(new SoneTemplatePage("emptyAlbumTitle.html", emptyAlbumTitleTemplate, "Page.EmptyAlbumTitle.Title", this))); pageToadlets.add(pageToadletFactory.createPageToadlet(new DismissNotificationPage(emptyTemplate, this))); pageToadlets.add(pageToadletFactory.createPageToadlet(new SoneTemplatePage("invalid.html", invalidTemplate, "Page.Invalid.Title", this))); - pageToadlets.add(pageToadletFactory.createPageToadlet(new StaticPage("css/", "/static/css/", "text/css"))); - pageToadlets.add(pageToadletFactory.createPageToadlet(new StaticPage("javascript/", "/static/javascript/", "text/javascript"))); - pageToadlets.add(pageToadletFactory.createPageToadlet(new StaticPage("images/", "/static/images/", "image/png"))); + pageToadlets.add(pageToadletFactory.createPageToadlet(loaders.loadStaticPage("css/", "/static/css/", "text/css"))); + pageToadlets.add(pageToadletFactory.createPageToadlet(loaders.loadStaticPage("javascript/", "/static/javascript/", "text/javascript"))); + pageToadlets.add(pageToadletFactory.createPageToadlet(loaders.loadStaticPage("images/", "/static/images/", "image/png"))); pageToadlets.add(pageToadletFactory.createPageToadlet(new TemplatePage("OpenSearch.xml", "application/opensearchdescription+xml", templateContextFactory, openSearchTemplate))); pageToadlets.add(pageToadletFactory.createPageToadlet(new GetImagePage(this))); pageToadlets.add(pageToadletFactory.createPageToadlet(new GetTranslationPage(this))); diff --git a/src/test/java/net/pterodactylus/sone/main/DebugLoadersTest.java b/src/test/java/net/pterodactylus/sone/main/DebugLoadersTest.java index 81a85a5..e9dfb71 100644 --- a/src/test/java/net/pterodactylus/sone/main/DebugLoadersTest.java +++ b/src/test/java/net/pterodactylus/sone/main/DebugLoadersTest.java @@ -2,13 +2,26 @@ package net.pterodactylus.sone.main; import static org.hamcrest.MatcherAssert.assertThat; import static org.hamcrest.Matchers.is; +import static org.hamcrest.Matchers.startsWith; +import static org.mockito.Mockito.mock; +import java.io.ByteArrayOutputStream; import java.io.File; import java.io.IOException; +import java.io.OutputStream; import java.io.StringWriter; +import java.net.URI; +import java.net.URISyntaxException; +import net.pterodactylus.sone.web.page.FreenetRequest; import net.pterodactylus.util.template.Template; import net.pterodactylus.util.template.TemplateContext; +import net.pterodactylus.util.web.Method; +import net.pterodactylus.util.web.Page; +import net.pterodactylus.util.web.Response; + +import freenet.clients.http.ToadletContext; +import freenet.support.api.HTTPRequest; import com.google.common.base.Charsets; import com.google.common.io.Files; @@ -29,22 +42,36 @@ public class DebugLoadersTest { private final StringWriter stringWriter = new StringWriter(); private final TemplateContext templateContext = new TemplateContext(); - private String templatePath; private Loaders loaders; @Before public void setupLoader() throws IOException { - templatePath = temporaryFolder.newFolder("temps").getPath(); + String templatePath = temporaryFolder.newFolder("temps").getPath(); loaders = new DebugLoaders(templatePath); + File templateFile = new File(templatePath, "template.txt"); + Files.write("<%if foo>foo<%else>bar<%/if>", templateFile, Charsets.UTF_8); } @Test public void debugLoaderCanLoadTemplatesFromFilesystem() throws IOException { - File templateFile = new File(templatePath, "template.txt"); - Files.write("<%if foo>foo<%else>bar<%/if>", templateFile, Charsets.UTF_8); Template template = loaders.loadTemplate("/template.txt"); template.render(templateContext, stringWriter); assertThat(stringWriter.toString(), is("bar")); } + @Test + public void staticPageIsServedFromFilesystem() throws URISyntaxException, IOException { + Page page = loaders.loadStaticPage("text/", "", "text/plain"); + URI uri = new URI("http://some.host/text/template.txt"); + Method method = Method.GET; + HTTPRequest httpRequest = mock(HTTPRequest.class); + ToadletContext toadletContext = mock(ToadletContext.class); + FreenetRequest request = new FreenetRequest(uri, method, httpRequest, toadletContext); + OutputStream outputStream = new ByteArrayOutputStream(); + Response response = new Response(outputStream); + page.handleRequest(request, response); + assertThat(response.getContentType(), startsWith("text/plain")); + assertThat(response.getStatusCode(), is(200)); + } + } diff --git a/src/test/java/net/pterodactylus/sone/main/DefaultLoadersTest.java b/src/test/java/net/pterodactylus/sone/main/DefaultLoadersTest.java index 220996d..59abf0a 100644 --- a/src/test/java/net/pterodactylus/sone/main/DefaultLoadersTest.java +++ b/src/test/java/net/pterodactylus/sone/main/DefaultLoadersTest.java @@ -2,11 +2,25 @@ package net.pterodactylus.sone.main; import static org.hamcrest.MatcherAssert.assertThat; import static org.hamcrest.Matchers.is; +import static org.hamcrest.Matchers.startsWith; +import static org.mockito.Mockito.mock; +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.io.OutputStream; import java.io.StringWriter; +import java.net.URI; +import java.net.URISyntaxException; +import net.pterodactylus.sone.web.page.FreenetRequest; import net.pterodactylus.util.template.Template; import net.pterodactylus.util.template.TemplateContext; +import net.pterodactylus.util.web.Method; +import net.pterodactylus.util.web.Page; +import net.pterodactylus.util.web.Response; + +import freenet.clients.http.ToadletContext; +import freenet.support.api.HTTPRequest; import org.junit.Test; @@ -28,4 +42,19 @@ public class DefaultLoadersTest { assertThat(stringWriter.toString(), is("Template. bar\n")); } + @Test + public void staticPageIsServedFromClasspath() throws IOException, URISyntaxException { + Page staticPage = loaders.loadStaticPage("text/", "/net/pterodactylus/sone/main/", "text/plain"); + URI uri = new URI("http://some.host/text/template.txt"); + Method method = Method.GET; + HTTPRequest httpRequest = mock(HTTPRequest.class); + ToadletContext toadletContext = mock(ToadletContext.class); + FreenetRequest request = new FreenetRequest(uri, method, httpRequest, toadletContext); + OutputStream outputStream = new ByteArrayOutputStream(); + Response response = new Response(outputStream); + staticPage.handleRequest(request, response); + assertThat(response.getContentType(), startsWith("text/plain")); + assertThat(response.getStatusCode(), is(200)); + } + } diff --git a/template.txt b/template.txt new file mode 100644 index 0000000..a26591c --- /dev/null +++ b/template.txt @@ -0,0 +1 @@ +<%if foo>foo<%else>bar<%/if> \ No newline at end of file -- 2.7.4