Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Some browsers appear to cache 302 requests in violation of RFC (I'm looking at you, Chrome: http://code.google.com/p/chromium/issues/detail?id=103458) I also saw this behavior with Firefox, even though I couldn't locate any bug report. Sine Chrome alone is a big enough browser share, in this change I modified the code to avoid 302 redirects and instead to service the request with 200. To avoid excessive data transfer, ETag is used to detect that the browser has the image in cache.
- Loading branch information
Showing
3 changed files
with
112 additions
and
20 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
71 changes: 71 additions & 0 deletions
71
src/main/java/org/jenkinsci/plugins/badge/StatusImage.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,71 @@ | ||
package org.jenkinsci.plugins.badge; | ||
|
||
import hudson.util.IOUtils; | ||
import jenkins.model.Jenkins; | ||
import org.kohsuke.stapler.HttpResponse; | ||
import org.kohsuke.stapler.StaplerRequest; | ||
import org.kohsuke.stapler.StaplerResponse; | ||
|
||
import javax.servlet.ServletException; | ||
import java.io.IOException; | ||
import java.io.InputStream; | ||
import java.net.URL; | ||
|
||
import static javax.servlet.http.HttpServletResponse.*; | ||
|
||
/** | ||
* Status image as an {@link HttpResponse}, with proper cache handling. | ||
* | ||
* <p> | ||
* Originally we used 302 redirects to map the status URL to a proper permanent image URL, | ||
* but it turns out that some browsers cache 302 redirects in violation of RFC | ||
* (see http://code.google.com/p/chromium/issues/detail?id=103458) | ||
* | ||
* <p> | ||
* So this version directly serves the image at the status URL. Since the status | ||
* can change any time, we use ETag to skip the actual data transfer if possible. | ||
* | ||
* @author Kohsuke Kawaguchi | ||
*/ | ||
class StatusImage implements HttpResponse { | ||
private final byte[] payload; | ||
|
||
/** | ||
* To improve the caching, compute unique ETag. | ||
* | ||
* This needs to differentiate different image types, and possible future image changes | ||
* in newer versions of this plugin. | ||
*/ | ||
private final String etag; | ||
|
||
private final String length; | ||
|
||
StatusImage(String fileName) throws IOException { | ||
etag = Jenkins.RESOURCE_PATH+'/'+fileName; | ||
|
||
URL image = new URL( | ||
Jenkins.getInstance().pluginManager.getPlugin("embeddable-build-status").baseResourceURL, | ||
"status/"+fileName); | ||
InputStream s = image.openStream(); | ||
try { | ||
payload = IOUtils.toByteArray(s); | ||
} finally { | ||
IOUtils.closeQuietly(s); | ||
} | ||
length = Integer.toString(payload.length); | ||
} | ||
|
||
public void generateResponse(StaplerRequest req, StaplerResponse rsp, Object node) throws IOException, ServletException { | ||
String v = req.getHeader("If-None-Match"); | ||
if (etag.equals(v)) { | ||
rsp.setStatus(SC_NOT_MODIFIED); | ||
return; | ||
} | ||
|
||
rsp.setHeader("ETag",etag); | ||
rsp.setHeader("Expires","Fri, 01 Jan 1984 00:00:00 GMT"); | ||
rsp.setHeader("Content-Type", "image/png"); | ||
rsp.setHeader("Content-Length", length); | ||
rsp.getOutputStream().write(payload); | ||
} | ||
} |