Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@
import org.apache.roller.weblogger.business.MediaFileManager;
import org.apache.roller.weblogger.business.WebloggerFactory;

import java.io.InputStream;
import java.util.Date;
import java.util.List;
import org.apache.roller.weblogger.pojos.MediaFile;
Expand Down Expand Up @@ -159,12 +160,57 @@ public ThemeResource getResource(String path) {
try {
MediaFileManager mmgr =
WebloggerFactory.getWeblogger().getMediaFileManager();
MediaFile mf = mmgr.getMediaFileByOriginalPath(
this.weblog, path);
MediaFile mediaFile = mmgr.getMediaFileByOriginalPath(this.weblog, path);
if (mediaFile != null) {
resource = new MediaFileThemeResource(mediaFile);
}
} catch (WebloggerException ex) {
// ignored, resource considered not found
}
return resource;
}

private static final class MediaFileThemeResource implements ThemeResource {
private final MediaFile mediaFile;

private MediaFileThemeResource(MediaFile mediaFile) {
this.mediaFile = mediaFile;
}

@Override
public String getName() {
return mediaFile.getName();
}

@Override
public String getPath() {
return mediaFile.getOriginalPath();
}

@Override
public long getLastModified() {
return mediaFile.getLastModified();
}

@Override
public long getLength() {
return mediaFile.getLength();
}

@Override
public InputStream getInputStream() {
return mediaFile.getInputStream();
}

@Override
public boolean isDirectory() {
return false;
}

@Override
public int compareTo(ThemeResource other) {
return getPath().compareTo(other.getPath());
}
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.apache.roller.util.RollerConstants;
import org.apache.roller.weblogger.util.MediaTypePolicy;
import org.apache.roller.weblogger.WebloggerException;
import org.apache.roller.weblogger.business.MediaFileManager;
import org.apache.roller.weblogger.business.WebloggerFactory;
Expand Down Expand Up @@ -116,7 +117,8 @@ public void doGet(HttpServletRequest request, HttpServletResponse response)

// set the content type based on whatever is in our web.xml mime defs
if (resourceRequest.isThumbnail()) {
response.setContentType("image/png");
MediaTypePolicy.applyResponseHeaders(response, "image/png",
mediaFile.getName());
try {
resourceStream = mediaFile.getThumbnailInputStream();
} catch (Exception e) {
Expand All @@ -131,7 +133,8 @@ public void doGet(HttpServletRequest request, HttpServletResponse response)
}

if (resourceStream == null) {
response.setContentType(mediaFile.getContentType());
MediaTypePolicy.applyResponseHeaders(response,
mediaFile.getContentType(), mediaFile.getName());
resourceStream = mediaFile.getInputStream();
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.apache.roller.weblogger.util.MediaTypePolicy;
import org.apache.roller.weblogger.WebloggerException;
import org.apache.roller.weblogger.business.MediaFileManager;
import org.apache.roller.weblogger.business.WebloggerFactory;
Expand Down Expand Up @@ -129,7 +130,9 @@ public void doGet(HttpServletRequest request, HttpServletResponse response)
}

// if not from theme then see if resource is in weblog's upload dir
boolean fromUploadedMedia = false;
if (resourceStream == null) {
fromUploadedMedia = true;
try {
MediaFileManager mmgr = WebloggerFactory.getWeblogger()
.getMediaFileManager();
Expand Down Expand Up @@ -160,8 +163,19 @@ public void doGet(HttpServletRequest request, HttpServletResponse response)
}

// set the content type based on whatever is in our web.xml mime defs
response.setContentType(this.context.getMimeType(resourceRequest
.getResourcePath()));
String resourceType = MediaTypePolicy.typeFromName(
resourceRequest.getResourcePath(), this.context::getMimeType);
if (fromUploadedMedia) {
// Uploaded through the media library, so it is governed by the
// same policy as any other media response.
MediaTypePolicy.applyResponseHeaders(response, resourceType,

@mraible mraible Aug 31, 2026

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

context.getMimeType() returns null for extensions not mapped in web.xml/the container, and applyResponseHeaders turns null into an octet-stream attachment. On master setContentType(null) left the type unset and the browser could still display the file; now any unmapped (or uppercase, on a case-sensitive container) extension downloads in the theme preview.

resourceRequest.getResourcePath());
} else {
// A theme resource: authored as part of the theme and served as
// the type the theme intends, but never re-typed by the browser.
response.setHeader("X-Content-Type-Options", "nosniff");
response.setContentType(resourceType);
}

try {
// ok, lets serve up the file
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.apache.roller.weblogger.util.MediaTypePolicy;
import org.apache.roller.weblogger.WebloggerException;
import org.apache.roller.weblogger.business.MediaFileManager;
import org.apache.roller.weblogger.business.WebloggerFactory;
Expand Down Expand Up @@ -125,7 +126,9 @@ public void doGet(HttpServletRequest request, HttpServletResponse response)
}

// if not from theme then see if resource is in weblog's upload dir
boolean fromUploadedMedia = false;
if (resourceStream == null) {
fromUploadedMedia = true;
try {
MediaFileManager mmgr = WebloggerFactory.getWeblogger()
.getMediaFileManager();
Expand Down Expand Up @@ -159,8 +162,19 @@ public void doGet(HttpServletRequest request, HttpServletResponse response)
}

// set the content type based on whatever is in our web.xml mime defs
response.setContentType(this.context.getMimeType(resourceRequest
.getResourcePath()));
String resourceType = MediaTypePolicy.typeFromName(
resourceRequest.getResourcePath(), this.context::getMimeType);
if (fromUploadedMedia) {
// Uploaded through the media library, so it is governed by the

@mraible mraible Aug 31, 2026

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This branch is also where customized-theme resources land: WeblogCustomTheme.getResource() looks up the media file but never assigns it to resource, so it always returns null, and importTheme stores theme CSS/JS as media files with their original path. resourceType for css/bootstrap.css is text/css, which isn't inline-safe, so the stylesheet goes out as an octet-stream attachment with nosniff and the browser drops it. Fixing WeblogCustomTheme.getResource to return the media file would route these through the theme branch above; alternatively, treat text/css / text/javascript from the servlet-context mime table as theme-authored here as the description already promises.

// same policy as any other media response.
MediaTypePolicy.applyResponseHeaders(response, resourceType,
resourceRequest.getResourcePath());
} else {
// A theme resource: authored as part of the theme and served as
// the type the theme intends, but never re-typed by the browser.
response.setHeader("X-Content-Type-Options", "nosniff");
response.setContentType(resourceType);
}

try {
// ok, lets serve up the file
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -33,8 +33,10 @@
import org.apache.roller.weblogger.config.WebloggerRuntimeConfig;
import org.apache.roller.weblogger.pojos.MediaFile;
import org.apache.roller.weblogger.pojos.MediaFileDirectory;
import org.apache.roller.weblogger.ui.core.RollerContext;
import org.apache.roller.weblogger.util.RollerMessages;
import org.apache.roller.weblogger.util.RollerMessages.RollerMessage;
import org.apache.roller.weblogger.util.MediaTypePolicy;
import org.apache.roller.weblogger.util.Utilities;
import org.apache.struts2.interceptor.validation.SkipValidation;

Expand Down Expand Up @@ -173,23 +175,19 @@ public String save() {
mediaFile.setLength(this.uploadedFiles[i].length());
mediaFile.setInputStream(new FileInputStream(
this.uploadedFiles[i]));
mediaFile
.setContentType(this.uploadedFilesContentType[i]);

// in some cases Struts2 is not able to guess the content
// type correctly and assigns the default, which is
// octet-stream. So in cases where we see octet-stream
// we double check and see if we can guess the content
// type via the Java MIME type facilities.
mediaFile.setContentType(this.uploadedFilesContentType[i]);
if (mediaFile.getContentType() == null
|| mediaFile.getContentType().endsWith("/octet-stream")) {

String ctype = Utilities.getContentTypeFromFileName(mediaFile.getName());
if (null != ctype) {
mediaFile.setContentType(ctype);
}
// The type the browser put on the part describes what
// the sender meant to send. It is taken as a hint and
// the stored type is worked out from the file name.
String declaredType = MediaTypePolicy.normalizeType(
this.uploadedFilesContentType[i]);
if (!WebloggerFactory.getWeblogger().getFileContentManager().canSave(
getActionWeblog(), fileName, declaredType,
this.uploadedFiles[i].length(), errors)) {
continue;
}
mediaFile.setContentType(MediaTypePolicy.storedTypeFor(
mediaFile.getName(), declaredType,
RollerContext.getServletContext()::getMimeType));

manager.createMediaFile(getActionWeblog(), mediaFile, errors);
WebloggerFactory.getWeblogger().flush();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,12 +23,15 @@
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.apache.roller.weblogger.util.MediaTypePolicy;
import org.apache.roller.weblogger.WebloggerException;
import org.apache.roller.weblogger.business.FileIOException;
import org.apache.roller.weblogger.business.MediaFileManager;
import org.apache.roller.weblogger.business.WebloggerFactory;
import org.apache.roller.weblogger.pojos.MediaFile;
import org.apache.roller.weblogger.pojos.MediaFileDirectory;
import org.apache.roller.weblogger.ui.core.RollerContext;
import org.apache.roller.weblogger.util.RollerMessages;
import org.apache.struts2.convention.annotation.AllowedMethods;
import org.apache.struts2.interceptor.validation.SkipValidation;

Expand Down Expand Up @@ -123,8 +126,20 @@ public String save() {
bean.copyTo(mediaFile);

if (uploadedFile != null) {
mediaFile.setLength(this.uploadedFile.length());
mediaFile.setContentType(this.uploadedFileContentType);
mediaFile.setLength(this.uploadedFile.length());
String declaredType = MediaTypePolicy.normalizeType(
this.uploadedFileContentType);
RollerMessages errors = new RollerMessages();
if (!WebloggerFactory.getWeblogger().getFileContentManager().canSave(
getActionWeblog(), this.uploadedFileName, declaredType,
this.uploadedFile.length(), errors)) {
throw new FileIOException(errors.toString());
}
// Replacing the body re-decides the type, on the same
// terms as the original upload.
mediaFile.setContentType(MediaTypePolicy.storedTypeFor(
this.uploadedFileName, declaredType,
RollerContext.getServletContext()::getMimeType));
manager.updateMediaFile(getActionWeblog(), mediaFile,
new FileInputStream(this.uploadedFile));
} else {
Expand Down
Loading
Loading