From 5f307ecd2872f3dac176af6c5c611b2f6427cf6f Mon Sep 17 00:00:00 2001 From: srosse <none@none> Date: Wed, 22 Jan 2014 16:26:34 +0100 Subject: [PATCH] OO-947: use the solution defined by RFC2231/5987 to encode the filename in the headers --- .../modules/bc/components/CrumbRenderer.java | 3 +- .../core/gui/media/FileMediaResource.java | 4 +- .../gui/media/NamedFileMediaResource.java | 4 +- .../org/olat/core/gui/render/URLBuilder.java | 42 +++++++++++++------ .../java/org/olat/core/util/StringHelper.java | 24 +---------- .../olat/core/util/vfs/VFSMediaResource.java | 16 +++---- .../util/vfs/VFSRevisionMediaResource.java | 17 +++----- .../olat/course/archiver/ArchiveResource.java | 4 +- .../olat/course/db/CourseDBMediaResource.java | 5 ++- .../olat/ims/qti/export/QTIWordExport.java | 4 +- .../olat/ims/qti/qpool/QTIPoolWordExport.java | 4 +- .../manager/AbstractExportTestResource.java | 4 +- .../qpool/manager/ExportQItemResource.java | 5 ++- .../manager/ExportQItemsZipResource.java | 5 ++- 14 files changed, 65 insertions(+), 76 deletions(-) diff --git a/src/main/java/org/olat/core/commons/modules/bc/components/CrumbRenderer.java b/src/main/java/org/olat/core/commons/modules/bc/components/CrumbRenderer.java index f7a4e2bfc32..c9dc843954e 100644 --- a/src/main/java/org/olat/core/commons/modules/bc/components/CrumbRenderer.java +++ b/src/main/java/org/olat/core/commons/modules/bc/components/CrumbRenderer.java @@ -31,7 +31,6 @@ import java.util.StringTokenizer; import org.olat.core.gui.control.winmgr.AJAXFlags; import org.olat.core.gui.render.StringOutput; import org.olat.core.gui.render.URLBuilder; -import org.olat.core.util.StringHelper; /** * Initial Date: 08.07.2003 @@ -72,7 +71,7 @@ public class CrumbRenderer { StringTokenizer st = new StringTokenizer(fc.getCurrentContainerPath(), "/", false); while (st.hasMoreElements()) { String token = st.nextToken(); - pathLink.append(StringHelper.urlEncodeUTF8(token)); + pathLink.append(ubu.encodeUrl(token)); sb.append(" / "); if (st.hasMoreElements() && renderLinks) { sb.append("<a href=\""); diff --git a/src/main/java/org/olat/core/gui/media/FileMediaResource.java b/src/main/java/org/olat/core/gui/media/FileMediaResource.java index 860d8f93660..4ffb9fc521e 100644 --- a/src/main/java/org/olat/core/gui/media/FileMediaResource.java +++ b/src/main/java/org/olat/core/gui/media/FileMediaResource.java @@ -141,8 +141,8 @@ public class FileMediaResource implements MediaResource { if (deliverAsAttachment) { // encode filename in ISO8859-1; does not really help but prevents from filename not being displayed at all // if it contains non-US-ASCII characters which are not allowed in header fields. - hres.setHeader("Content-Disposition","attachment; filename=\"" + StringHelper.urlEncodeISO88591(file.getName()) + "\""); - hres.setHeader("Content-Description",StringHelper.urlEncodeISO88591(file.getName())); + hres.setHeader("Content-Disposition","attachment; filename*=UTF-8''" + StringHelper.urlEncodeUTF8(file.getName())); + hres.setHeader("Content-Description",StringHelper.urlEncodeUTF8(file.getName())); } else { hres.setHeader("Content-Disposition", "inline"); } diff --git a/src/main/java/org/olat/core/gui/media/NamedFileMediaResource.java b/src/main/java/org/olat/core/gui/media/NamedFileMediaResource.java index 454752eca4a..1d3f80b9935 100644 --- a/src/main/java/org/olat/core/gui/media/NamedFileMediaResource.java +++ b/src/main/java/org/olat/core/gui/media/NamedFileMediaResource.java @@ -84,8 +84,8 @@ public class NamedFileMediaResource extends FileMediaResource { public void prepare(HttpServletResponse hres) { // encode filename in ISO8859-1; does not really help but prevents from filename not being displayed at all // if it contains non-US-ASCII characters which are not allowed in header fields. - hres.setHeader("Content-Disposition","attachment; filename=\"" + StringHelper.urlEncodeISO88591(fileName) + "\""); - hres.setHeader("Content-Description",StringHelper.urlEncodeISO88591(fileDescription)); + hres.setHeader("Content-Disposition", "attachment; filename*=UTF-8''" + StringHelper.urlEncodeUTF8(fileName)); + hres.setHeader("Content-Description", StringHelper.urlEncodeUTF8(fileDescription)); } diff --git a/src/main/java/org/olat/core/gui/render/URLBuilder.java b/src/main/java/org/olat/core/gui/render/URLBuilder.java index eecfa312eb0..38a8abea9d1 100644 --- a/src/main/java/org/olat/core/gui/render/URLBuilder.java +++ b/src/main/java/org/olat/core/gui/render/URLBuilder.java @@ -26,18 +26,25 @@ package org.olat.core.gui.render; +import java.io.UnsupportedEncodingException; +import java.net.URLEncoder; +import java.util.regex.Pattern; + import org.olat.core.gui.GUIInterna; import org.olat.core.gui.UserRequest; import org.olat.core.gui.components.Component; import org.olat.core.gui.control.winmgr.AJAXFlags; import org.olat.core.gui.control.winmgr.WindowBackOfficeImpl; -import org.olat.core.util.StringHelper; +import org.olat.core.logging.AssertException; /** * * @author Felix Jost */ public class URLBuilder { + + private static final Pattern p1 = Pattern.compile("\\+"); + private static final Pattern p2 = Pattern.compile("%2F"); private final String uriPrefix; @@ -135,16 +142,6 @@ public class URLBuilder { else buf.append(quote); } - - /*public boolean isAjaxOn() { - return true; - }*/ - - /*public void buildNonAjaxURI(StringOutput buf, String[] keys, String[] values, String modURI) { - buildURI(buf, keys, values, modURI, AJAXFlags.MODE_TOBGIFRAME); - }*/ - - /** * builds an uri. neither key nor values may contain the character * UserRequest.PARAM_DELIM which is a ":" (colon). in case you think you @@ -184,7 +181,7 @@ public class URLBuilder { result.append('/'); if (modURI != null) result.append(modURI); //FIXME:fj:a urlEncodeUTF8 is slow; improve the regexp, also convert only the modURI to utf-8? - buf.append(StringHelper.urlEncodeUTF8(result.toString())); + buf.append(encodeUrl(result.toString())); } public void buildURI(StringOutput buf, String[] keys, String[] values, String modURI) { @@ -244,6 +241,27 @@ public class URLBuilder { */ return result; } + + /** + * @param url + * @return encoded string + */ + public String encodeUrl(String url) { + String encodedURL; + try { + encodedURL = URLEncoder.encode(url, "UTF-8"); + } catch (UnsupportedEncodingException e) { + /* + * from java.nio.Charset Standard charsets Every implementation of the + * Java platform is required to support the following standard charsets... + * ... UTF-8 Eight-bit UCS Transformation Format ... + */ + throw new AssertException("utf-8 encoding is needed for proper encoding, but not offered on this java platform????"); + } + encodedURL = p1.matcher(encodedURL).replaceAll("%20"); + encodedURL = p2.matcher(encodedURL).replaceAll("/"); + return encodedURL; + } /** * used for OLAT-1973 only: if in replayable-url-mode for performance testing diff --git a/src/main/java/org/olat/core/util/StringHelper.java b/src/main/java/org/olat/core/util/StringHelper.java index 2e65edb4d67..c3bc38653ca 100644 --- a/src/main/java/org/olat/core/util/StringHelper.java +++ b/src/main/java/org/olat/core/util/StringHelper.java @@ -68,9 +68,6 @@ public class StringHelper { private static final String WHITESPACE_REGEXP = "^\\s*$"; private static final Pattern WHITESPACE_PATTERN = Pattern.compile(WHITESPACE_REGEXP); - private static final Pattern p1 = Pattern.compile("\\+"); - private static final Pattern p2 = Pattern.compile("%2F"); - /** * regex for not allowing * <code>;,:</code> <code>ALL_WITHOUT_COMMA_2POINT_STRPNT</code> @@ -194,21 +191,7 @@ public class StringHelper { numFormatter.setMaximumFractionDigits(fractionDigits); return numFormatter.format(f); } - - /** - * @param url - * @return encoded string - */ - public static String urlEncodeISO88591(String url) { - String part; - try { - part = URLEncoder.encode(url, "iso-8859-1"); - } catch (UnsupportedEncodingException e) { - throw new RuntimeException("encoding failed (iso-8859-1) for :" + url); - } - return part; - } - + /** * @param url * @return encoded string @@ -225,13 +208,8 @@ public class StringHelper { */ throw new AssertException("utf-8 encoding is needed for proper encoding, but not offered on this java platform????"); } - encodedURL = p1.matcher(encodedURL).replaceAll("%20"); - encodedURL = p2.matcher(encodedURL).replaceAll("/"); return encodedURL; } - - - /** * Converts all keys of a hash map to a string array. diff --git a/src/main/java/org/olat/core/util/vfs/VFSMediaResource.java b/src/main/java/org/olat/core/util/vfs/VFSMediaResource.java index 1bd5932b0ee..9a1ebec95bb 100644 --- a/src/main/java/org/olat/core/util/vfs/VFSMediaResource.java +++ b/src/main/java/org/olat/core/util/vfs/VFSMediaResource.java @@ -27,14 +27,13 @@ package org.olat.core.util.vfs; import java.io.InputStream; -import java.io.UnsupportedEncodingException; -import java.net.URLEncoder; import javax.servlet.http.HttpServletResponse; import org.olat.core.CoreSpringFactory; import org.olat.core.commons.modules.bc.FilesInfoMBean; import org.olat.core.gui.media.MediaResource; +import org.olat.core.util.StringHelper; import org.olat.core.util.WebappHelper; public class VFSMediaResource implements MediaResource { @@ -93,15 +92,12 @@ public class VFSMediaResource implements MediaResource { * @see org.olat.core.gui.media.MediaResource#prepare(javax.servlet.http.HttpServletResponse) */ public void prepare(HttpServletResponse hres) { - //http headers are ASCII only therefore we encode filenames - String filename = ""; - try { - filename = URLEncoder.encode(vfsLeaf.getName(), "utf-8"); - } catch (UnsupportedEncodingException wontHappen) { - //nothing}; + String filename = StringHelper.urlEncodeUTF8(vfsLeaf.getName()); + if (unknownMimeType) { + hres.setHeader("Content-Disposition", "attachment; filename*=UTF-8''" + filename); + } else { + hres.setHeader("Content-Disposition", "filename*=UTF-8''" + filename); } - if (unknownMimeType) hres.setHeader("Content-Disposition", "attachment; filename=" + filename); - else hres.setHeader("Content-Disposition", "filename=" + filename); } public void release() { diff --git a/src/main/java/org/olat/core/util/vfs/VFSRevisionMediaResource.java b/src/main/java/org/olat/core/util/vfs/VFSRevisionMediaResource.java index f172b7056d7..b34b382ecab 100644 --- a/src/main/java/org/olat/core/util/vfs/VFSRevisionMediaResource.java +++ b/src/main/java/org/olat/core/util/vfs/VFSRevisionMediaResource.java @@ -20,12 +20,11 @@ package org.olat.core.util.vfs; import java.io.InputStream; -import java.io.UnsupportedEncodingException; -import java.net.URLEncoder; import javax.servlet.http.HttpServletResponse; import org.olat.core.gui.media.MediaResource; +import org.olat.core.util.StringHelper; import org.olat.core.util.WebappHelper; import org.olat.core.util.vfs.version.VFSRevision; @@ -77,16 +76,12 @@ public class VFSRevisionMediaResource implements MediaResource { } public void prepare(HttpServletResponse hres) { - String filename = ""; - try { - filename = URLEncoder.encode(revision.getName(), "utf-8"); - } catch (UnsupportedEncodingException wontHappen) { - //nothing + String filename = StringHelper.urlEncodeUTF8(revision.getName()); + if (forceDownload || unknownMimeType) { + hres.setHeader("Content-Disposition", "attachment; filename*=UTF-8''" + filename); + } else { + hres.setHeader("Content-Disposition", "filename*=UTF-8''" + filename); } - if (forceDownload || unknownMimeType) - hres.setHeader("Content-Disposition", "attachment; filename=" + filename); - else - hres.setHeader("Content-Disposition", "filename=" + filename); } public void release() { diff --git a/src/main/java/org/olat/course/archiver/ArchiveResource.java b/src/main/java/org/olat/course/archiver/ArchiveResource.java index afd4f5998fc..5f024910033 100644 --- a/src/main/java/org/olat/course/archiver/ArchiveResource.java +++ b/src/main/java/org/olat/course/archiver/ArchiveResource.java @@ -93,8 +93,8 @@ public class ArchiveResource implements MediaResource { + StringHelper.transformDisplayNameToFileSystemName(courseNode.getShortName()) + "_" + Formatter.formatDatetimeFilesystemSave(new Date(System.currentTimeMillis())) + ".zip"; - String urlEncodedLabel = StringHelper.urlEncodeISO88591(label); - hres.setHeader("Content-Disposition","attachment; filename=\"" + urlEncodedLabel + "\""); + String urlEncodedLabel = StringHelper.urlEncodeUTF8(label); + hres.setHeader("Content-Disposition","attachment; filename*=UTF-8''" + urlEncodedLabel); hres.setHeader("Content-Description", urlEncodedLabel); ZipOutputStream zout = null; diff --git a/src/main/java/org/olat/course/db/CourseDBMediaResource.java b/src/main/java/org/olat/course/db/CourseDBMediaResource.java index 4ad40aefc5d..45e0c3fbda5 100644 --- a/src/main/java/org/olat/course/db/CourseDBMediaResource.java +++ b/src/main/java/org/olat/course/db/CourseDBMediaResource.java @@ -70,8 +70,9 @@ public class CourseDBMediaResource implements MediaResource { @Override public void prepare(HttpServletResponse hres) { - hres.setHeader("Content-Disposition","filename=\"" + StringHelper.urlEncodeISO88591(fileName) + "\""); - hres.setHeader("Content-Description",StringHelper.urlEncodeISO88591(fileName)); + String encodedFileName = StringHelper.urlEncodeUTF8(fileName); + hres.setHeader("Content-Disposition","filename*=UTF-8''" + encodedFileName); + hres.setHeader("Content-Description",encodedFileName); } diff --git a/src/main/java/org/olat/ims/qti/export/QTIWordExport.java b/src/main/java/org/olat/ims/qti/export/QTIWordExport.java index d60379bce2f..9e2eddccaa3 100644 --- a/src/main/java/org/olat/ims/qti/export/QTIWordExport.java +++ b/src/main/java/org/olat/ims/qti/export/QTIWordExport.java @@ -122,8 +122,8 @@ public class QTIWordExport implements MediaResource { String secureLabel = StringHelper.transformDisplayNameToFileSystemName(label); String file = secureLabel + ".zip"; - hres.setHeader("Content-Disposition","attachment; filename=\"" + StringHelper.urlEncodeISO88591(file) + "\""); - hres.setHeader("Content-Description",StringHelper.urlEncodeISO88591(label)); + hres.setHeader("Content-Disposition", "attachment; filename*=UTF-8''" + StringHelper.urlEncodeUTF8(file)); + hres.setHeader("Content-Description", StringHelper.urlEncodeUTF8(label)); zout = new ZipOutputStream(hres.getOutputStream()); zout.setLevel(9); diff --git a/src/main/java/org/olat/ims/qti/qpool/QTIPoolWordExport.java b/src/main/java/org/olat/ims/qti/qpool/QTIPoolWordExport.java index c47cbb6a0fa..fdc91bb8ee2 100644 --- a/src/main/java/org/olat/ims/qti/qpool/QTIPoolWordExport.java +++ b/src/main/java/org/olat/ims/qti/qpool/QTIPoolWordExport.java @@ -122,8 +122,8 @@ class QTIPoolWordExport implements MediaResource { List<QuestionItemFull> fullItems = questionItemDao.loadByIds(itemKeys); String file = secureLabel + ".zip"; - hres.setHeader("Content-Disposition","attachment; filename=\"" + StringHelper.urlEncodeISO88591(file) + "\""); - hres.setHeader("Content-Description",StringHelper.urlEncodeISO88591(label)); + hres.setHeader("Content-Disposition","attachment; filename*=UTF-8''" + StringHelper.urlEncodeUTF8(file)); + hres.setHeader("Content-Description", StringHelper.urlEncodeUTF8(label)); zout = new ZipOutputStream(hres.getOutputStream()); zout.setLevel(9); diff --git a/src/main/java/org/olat/modules/qpool/manager/AbstractExportTestResource.java b/src/main/java/org/olat/modules/qpool/manager/AbstractExportTestResource.java index dd433c7bf67..195ead4bc34 100644 --- a/src/main/java/org/olat/modules/qpool/manager/AbstractExportTestResource.java +++ b/src/main/java/org/olat/modules/qpool/manager/AbstractExportTestResource.java @@ -85,8 +85,8 @@ public abstract class AbstractExportTestResource implements MediaResource { String label = "Test"; String file = StringHelper.transformDisplayNameToFileSystemName(label) + ".zip"; - hres.setHeader("Content-Disposition","attachment; filename=\"" + StringHelper.urlEncodeISO88591(file) + "\""); - hres.setHeader("Content-Description",StringHelper.urlEncodeISO88591(label)); + hres.setHeader("Content-Disposition", "attachment; filename*=UTF-8''" + StringHelper.urlEncodeUTF8(file)); + hres.setHeader("Content-Description", StringHelper.urlEncodeUTF8(label)); ZipOutputStream zout = null; try { diff --git a/src/main/java/org/olat/modules/qpool/manager/ExportQItemResource.java b/src/main/java/org/olat/modules/qpool/manager/ExportQItemResource.java index 540d0b32e98..654e814424f 100644 --- a/src/main/java/org/olat/modules/qpool/manager/ExportQItemResource.java +++ b/src/main/java/org/olat/modules/qpool/manager/ExportQItemResource.java @@ -84,8 +84,9 @@ public class ExportQItemResource implements MediaResource { String label = item.getTitle(); String file = StringHelper.transformDisplayNameToFileSystemName(label) + ".zip"; - hres.setHeader("Content-Disposition","attachment; filename=\"" + StringHelper.urlEncodeISO88591(file) + "\""); - hres.setHeader("Content-Description",StringHelper.urlEncodeISO88591(label)); + String encodedFileName = StringHelper.urlEncodeUTF8(file); + hres.setHeader("Content-Disposition", "attachment; filename*=UTF-8''" + encodedFileName); + hres.setHeader("Content-Description", encodedFileName); ZipOutputStream zout = null; try { diff --git a/src/main/java/org/olat/modules/qpool/manager/ExportQItemsZipResource.java b/src/main/java/org/olat/modules/qpool/manager/ExportQItemsZipResource.java index 51f3fd1cf6a..df8c1cbc668 100644 --- a/src/main/java/org/olat/modules/qpool/manager/ExportQItemsZipResource.java +++ b/src/main/java/org/olat/modules/qpool/manager/ExportQItemsZipResource.java @@ -85,8 +85,9 @@ public class ExportQItemsZipResource implements MediaResource { String label = "ExportItems"; String file = StringHelper.transformDisplayNameToFileSystemName(label) + ".zip"; - hres.setHeader("Content-Disposition","attachment; filename=\"" + StringHelper.urlEncodeISO88591(file) + "\""); - hres.setHeader("Content-Description",StringHelper.urlEncodeISO88591(label)); + String encodedFileName = StringHelper.urlEncodeUTF8(file); + hres.setHeader("Content-Disposition", "attachment; filename*=UTF-8''" + encodedFileName); + hres.setHeader("Content-Description", encodedFileName); ZipOutputStream zout = null; try { -- GitLab