Skip to content

Instantly share code, notes, and snippets.

@danielalexiuc
Created June 6, 2012 14:54
Show Gist options
  • Star 12 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save danielalexiuc/2882360 to your computer and use it in GitHub Desktop.
Save danielalexiuc/2882360 to your computer and use it in GitHub Desktop.
Here's how to get static resources minified and gzipped. Most addons and plugins I've seen don't handle static resources. Stick this file anywhere in the classpath (I put it in "util" directory) and stick the play.plugins file into your conf directory.
1003:util.StaticGzipPlugin
package util;
import com.google.common.io.Files;
import play.Logger;
import play.Play;
import play.PlayPlugin;
import play.libs.MimeTypes;
import play.mvc.Http;
import play.utils.Utils;
import play.vfs.VirtualFile;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.IOException;
import java.nio.charset.Charset;
import java.util.Date;
import static org.jboss.netty.handler.codec.http.HttpHeaders.Names.*;
import static util.Compression.*;
public class StaticGzipPlugin extends PlayPlugin {
@Override
public boolean serveStatic(VirtualFile file, Http.Request request, Http.Response response) {
try {
final File localFile = file.getRealFile();
String contentType = MimeTypes.getContentType(localFile.getName(), "text/plain");
// ignore images, I was having trouble when gzipping them. They probably don't need it anyway.
if (contentType.contains("image")) return false;
response.setContentTypeIfNotSet(contentType);
response = addEtag(request, response, localFile);
// minify
String content = minify(request, response, localFile);
// gzip only if supported and not excluded
if (isGzipSupported(request) && !isExcludedAction(request)) {
final ByteArrayOutputStream gzip = getGzipStream(content);
// set response header
response.setHeader("Content-Encoding", "gzip");
response.setHeader("Content-Length", gzip.size() + "");
response.out = gzip;
return true;
} else {
response.out = new ByteArrayOutputStream(content.length());
response.out.write(content.getBytes());
return true;
}
} catch (Exception e) {
Logger.error(e, "Error when Gzipping response: %s", e.getMessage());
}
return false;
}
private String minify(Http.Request request, Http.Response response, File file) throws IOException {
String content = Files.toString(file, Charset.defaultCharset());
if (!isExcludedAction(request)) {
// select compression method by contentType
if (response.contentType.contains("text/html")) { // could be "text/html; charset=utf-8"
return Compression.compressHTML(content);
} else if (response.contentType.contains("text/xml")) {
return Compression.compressXML(content);
} else if (response.contentType.contains("text/css")) {
return Compression.compressCSS(content);
} else if (response.contentType.contains("text/javascript")
|| response.contentType.contains("application/javascript")) {
return Compression.compressJS(content);
}
}
return content;
}
private static Http.Response addEtag(Http.Request request, Http.Response response, File file) {
if (Play.mode == Play.Mode.DEV) {
response.setHeader(CACHE_CONTROL, "no-cache");
} else {
String maxAge = Play.configuration.getProperty("http.cacheControl", "3600");
if (maxAge.equals("0")) {
response.setHeader(CACHE_CONTROL, "no-cache");
} else {
response.setHeader(CACHE_CONTROL, "max-age=" + maxAge);
}
}
boolean useEtag = Play.configuration.getProperty("http.useETag", "true").equals("true");
last = (file.lastModified() / 1000) * 1000
final String etag = "\"" + last + "-" + file.hashCode() + "\"";
if (!request.isModified(etag, last)) {
if (request.method.equals("GET")) {
response.status = Http.StatusCode.NOT_MODIFIED;
}
if (useEtag) {
response.setHeader(ETAG, etag);
}
} else {
response.setHeader(LAST_MODIFIED, Utils.getHttpDateFormatter().format(new Date(last)));
if (useEtag) {
response.setHeader(ETAG, etag);
}
}
return response;
}
}
Copy link

ghost commented Aug 21, 2012

Nice work!
I should have found this earlier.
Any license for this? I want to include it in minifymod

greets,
maklemenz

@isamaru
Copy link

isamaru commented Sep 9, 2012

Hey, there's a little bug in there: last can give you an accuracy of miliseconds, which gets truncated to seconds when passed into header. When comparing it with request.isModified(etag, last), these additional miliseconds make the file seem newer. This means that the application virtually never returns "NOT MODIFIED". Using this fixed it for me:

last = (file.lastModified() / 1000) * 1000

@danielalexiuc
Copy link
Author

Sorry guys I didn't get any notification of your comments - do I have to star my own gist to get notifications of comments?

Thanks for the bugfix - please do whatever you like with this code.

@danielalexiuc
Copy link
Author

Sorry guys I didn't get any notification of your comments - do I have to star my own gist to get notifications of comments?

Thanks for the bugfix - please do whatever you like with this code.

@danielalexiuc
Copy link
Author

Sorry guys I didn't get any notification of your comments - do I have to star my own gist to get notifications of comments?

Thanks for the bugfix - please do whatever you like with this code.

@danielalexiuc
Copy link
Author

Sorry guys I didn't get any notification of your comments - do I have to star my own gist to get notifications of comments?

Thanks for the bugfix - please do whatever you like with this code.

@danielalexiuc
Copy link
Author

Sorry guys I didn't get any notification of your comments - do I have to star my own gist to get notifications of comments?

Thanks for the bugfix - please do whatever you like with this code.

@danielalexiuc
Copy link
Author

Sorry guys I didn't get any notification of your comments - do I have to star my own gist to get notifications of comments?

Thanks for the bugfix - please do whatever you like with this code.

@danielalexiuc
Copy link
Author

Sorry guys I didn't get any notification of your comments - do I have to star my own gist to get notifications of comments?

Thanks for the bugfix - please do whatever you like with this code.

@danielalexiuc
Copy link
Author

Sorry guys I didn't get any notification of your comments - do I have to star my own gist to get notifications of comments?

Thanks for the bugfix - please do whatever you like with this code.

@danielalexiuc
Copy link
Author

Sorry guys I didn't get any notification of your comments - do I have to star my own gist to get notifications of comments?

Thanks for the bugfix - please do whatever you like with this code.

@danielalexiuc
Copy link
Author

Sorry guys I didn't get any notification of your comments - do I have to star my own gist to get notifications of comments?

Thanks for the bugfix - please do whatever you like with this code.

@danielalexiuc
Copy link
Author

Sorry guys I didn't get any notification of your comments - do I have to star my own gist to get notifications of comments?

Thanks for the bugfix - please do whatever you like with this code.

@danielalexiuc
Copy link
Author

Sorry guys I didn't get any notification of your comments - do I have to star my own gist to get notifications of comments?

Thanks for the bugfix - please do whatever you like with this code.

@danielalexiuc
Copy link
Author

Sorry guys I didn't get any notification of your comments - do I have to star my own gist to get notifications of comments?

Thanks for the bugfix - please do whatever you like with this code.

@danielalexiuc
Copy link
Author

Sorry guys I didn't get any notification of your comments - do I have to star my own gist to get notifications of comments?

Thanks for the bugfix - please do whatever you like with this code.

@danielalexiuc
Copy link
Author

Sorry guys I didn't get any notification of your comments - do I have to star my own gist to get notifications of comments?

Thanks for the bugfix - please do whatever you like with this code.

@danielalexiuc
Copy link
Author

Sorry guys I didn't get any notification of your comments - do I have to star my own gist to get notifications of comments?

Thanks for the bugfix - please do whatever you like with this code.

@danielalexiuc
Copy link
Author

GITHUB COMMENTING SYSTEM

ლ(ಠ益ಠლ)

Y U NO WORK CORRECTLY?

@vudayas
Copy link

vudayas commented Oct 5, 2012

this doesn't compile

Copy link

ghost commented Oct 18, 2012

"this doesn't compile"
It has dependencies. Look at the play-minifymod. You should find everything you need to compile this.

@manish333999
Copy link

what the heck! with Play 2.0....
response.setHeader .... should be " response().setHeader ... " I spent 15 minutes trying to debug that bad compile!
On other thoughts was that on purpose??????

@danielalexiuc
Copy link
Author

@manish333999 you spent 15 minutes debugging something that wouldn't compile?

This was written for Play 1.2.4 - I haven't tried it with Play 2.

@danielalexiuc
Copy link
Author

Looks like the addEtag() method causes problems with Safari. Be careful with it, or disable it until I can figure out a fix: http://stackoverflow.com/questions/16824862/heroku-hosted-html-times-out-after-1-minute-on-safari-only-every-second-time

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment