Skip to content

Instantly share code, notes, and snippets.

@suprememoocow
Created December 16, 2011 15:12
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 1 You must be signed in to fork a gist
  • Save suprememoocow/1486409 to your computer and use it in GitHub Desktop.
Save suprememoocow/1486409 to your computer and use it in GitHub Desktop.
DataBounce: server-side workaround for data: url problems in Internet Explorer. Full example at https://github.com/suprememoocow/databounce
var DataBounce = function(dataUrl, config) {
config = config || {};
var defaults = {
formName: "exportform",
filename: "",
exportFrameName: "exportFrame",
postUrl: "dataBounce"
};
/** Apply defaults to the config */
for(var key in defaults) {
if(!config[key]) {
config[key] = defaults[key];
}
}
var isIE = function() {
return navigator.appName == 'Microsoft Internet Explorer';
};
var createExportElements = function() {
/** This code will only ever be used in IE, so it uses well-known workarounds to internet explorer bugs (which won't work in other browsers) */
var iframe = document.createElement("<IFRAME name='" + config.exportFrameName + "'>");
iframe.id = config.exportFrameName;
iframe.style.display = "none";
document.body.appendChild(iframe);
var form = document.createElement("form");
form.id = config.exportFrameName;
form.method = "post";
form.action = config.postUrl;
form.style.display = "none";
form.target = config.exportFrameName;
var filename = document.createElement("<input name='filename'>");
filename.type = "hidden";
var data = document.createElement("<input name='data'>");
data.type = "hidden";
form.appendChild(filename);
form.appendChild(data);
document.body.appendChild(form);
iframe.setAttribute("name", config.exportFrameName);
return form;
}
return {
open: function() {
if(isIE()) {
var form = document.getElementById(config.formName);
if(form == null) {
form = createExportElements();
}
var dataElement = form.elements['data'];
var filenameElement = form.elements['filename'];
dataElement.value = dataUrl;
filenameElement.value = config.filename;
form.submit();
} else {
window.location.href = dataUrl;
}
}
}
}
package me.newdigate.databounce;
import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.net.MalformedURLException;
import java.net.URL;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import javax.servlet.ServletConfig;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.xml.bind.DatatypeConverter;
/**
* Allow Internet Explorer to download data url files larger than ~2k
*/
public class DataBounceServlet extends HttpServlet {
private static final String REQUIRE_LOGGED_IN_USER_PARAM = "requireLoggedInUser";
private static final String FILENAME_PARAM = "filename";
private static final String DEFAULT_MIME_TYPE = "application/octet-stream";
private static final String DEFAULT_CHARSET = "US-ASCII";
private static final long serialVersionUID = -3930208419053616713L;
private String defaultFileName;
private boolean requireLoggedInUser;
/**
* Initialise default values
*/
@Override
public void init(ServletConfig config) throws ServletException {
super.init(config);
defaultFileName = getInitParameter(FILENAME_PARAM);
String requireLoggedInUserStr = getInitParameter(REQUIRE_LOGGED_IN_USER_PARAM);
requireLoggedInUser = requireLoggedInUserStr == null ? false : new Boolean(requireLoggedInUserStr);
}
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
verifyRequest(req);
DataBounceRequest request = new DataBounceRequest(req);
if (request.filename == null) {
resp.setHeader("Content-Disposition", "attachment");
} else {
resp.setHeader("Content-Disposition", "attachment; filename=" + request.filename);
}
resp.setContentType(request.mimeType);
resp.getOutputStream().print(request.data);
}
/**
* Verify that this request is valid
*/
protected void verifyRequest(HttpServletRequest req) throws ServletException, MalformedURLException {
if (requireLoggedInUser) {
if (req.getRemoteUser() == null) {
throw new ServletException("This servlet can only be used by logged in users");
}
}
String referrer = req.getHeader("Referer");
URL x = new URL(referrer);
if (!req.getServerName().equals(x.getHost())) {
throw new ServletException("This servlet can only be used locally.");
}
}
/**
* Parse the data url
*/
class DataBounceRequest {
private final String mimeType;
private final String charSet;
private final String data;
private final String filename;
public DataBounceRequest(HttpServletRequest req) throws ServletException, UnsupportedEncodingException {
String requestData = req.getParameter("data");
if (requestData == null || !requestData.startsWith("data:")) {
throw new ServletException("Invalid format");
}
requestData = requestData.substring(5);
String requestFilename = req.getParameter(FILENAME_PARAM);
this.filename = requestFilename == null ? defaultFileName : requestFilename;
if (requestData == null) {
throw new ServletException("No data supplied");
}
String[] a = requestData.split(",", 2);
if (a.length != 2) {
throw new ServletException("Illegal data format");
}
String header = a[0];
List<String> headers = new ArrayList<String>(Arrays.asList(header.split(";")));
if (headers.size() > 0) {
mimeType = headers.remove(0);
} else {
mimeType = DEFAULT_MIME_TYPE;
}
boolean base64 = headers.remove("base64");
if (!headers.isEmpty()) {
String contentTypeHeader = headers.remove(0);
String[] contentTypeArray = contentTypeHeader.split("=", 2);
if (!"charset".equals(contentTypeArray[0])) {
throw new ServletException("Illegal data format");
}
charSet = contentTypeArray[1];
} else {
charSet = DEFAULT_CHARSET;
}
/* More, unexpected, headers? */
if (!headers.isEmpty()) {
throw new ServletException("Illegal data format");
}
/* Decode base64 if required */
String content = a[1];
if (base64) {
byte[] b = DatatypeConverter.parseBase64Binary(content);
this.data = new String(b, charSet);
} else {
this.data = content;
}
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment