diff --git a/xwiki-platform-core/xwiki-platform-oldcore/src/main/java/com/xpn/xwiki/web/SkinAction.java b/xwiki-platform-core/xwiki-platform-oldcore/src/main/java/com/xpn/xwiki/web/SkinAction.java index a1188f6..f96ce22 100644 --- a/xwiki-platform-core/xwiki-platform-oldcore/src/main/java/com/xpn/xwiki/web/SkinAction.java +++ b/xwiki-platform-core/xwiki-platform-oldcore/src/main/java/com/xpn/xwiki/web/SkinAction.java @@ -235,7 +235,8 @@ private boolean renderSkin(String filename, XWikiDocument doc, XWikiContext cont if (doc.isNew()) { LOGGER.debug("[{}] is not a document", doc.getDocumentReference().getName()); } else { - return renderFileFromObjectField(filename, doc, context) + return renderFileFromOverriddenTemplate(filename, doc, context) + || renderFileFromObjectField(filename, doc, context) || renderFileFromAttachment(filename, doc, context) || (SKINS_DIRECTORY.equals(doc.getSpace()) && renderFileFromFilesystem( getSkinFilePath(filename, doc.getName()), context)); @@ -327,44 +328,101 @@ public boolean renderFileFromObjectField(String filename, XWikiDocument doc, fin { LOGGER.debug("... as object property"); - BaseObject object = doc.getObject("XWiki.XWikiSkins"); - String content = null; - if (object != null) { - content = object.getStringValue(filename); + DocumentReference classReference = + new DocumentReference(doc.getDocumentReference().getWikiReference().getName(), "XWiki", "XWikiSkins"); + + BaseObject object = doc.getXObject(classReference); + if (object == null) { + LOGGER.debug("Object not found"); + return false; } + + return renderFileFromObjectProperty(object, filename, filename, doc, context); + } - if (!StringUtils.isBlank(content)) { - XWiki xwiki = context.getWiki(); - - // Evaluate the file only if it's of a supported type. - String mimetype = xwiki.getEngineContext().getMimeType(filename.toLowerCase()); - if (isCssMimeType(mimetype) || isJavascriptMimeType(mimetype)) { - final ObjectPropertyReference propertyReference = - new ObjectPropertyReference(filename, object.getReference()); + /** + * Tries to serve the content of an overridden template as a skin file. + * + * @param filename The name of the skin file that should be rendered. + * @param doc The skin {@link XWikiDocument document}. + * @param context The current {@link XWikiContext request context}. + * @return true if the object exists, and the field is set to a non-empty value, and its content was + * successfully sent. + * @throws IOException If the response cannot be sent. + * + * @since 7.4.1 + */ + private boolean renderFileFromOverriddenTemplate(String filename, XWikiDocument doc, final XWikiContext context) + throws IOException + { + LOGGER.debug("... as overridden template property"); + + DocumentReference classReference = + new DocumentReference(doc.getDocumentReference().getWikiReference().getName(), "XWiki", + "XWikiSkinFileOverrideClass"); + + BaseObject object = doc.getXObject(classReference, "path", filename); + if (object == null) { + LOGGER.debug("Overridden template not found"); + return false; + } - // Evaluate the content with the rights of the document's author. - content = evaluateVelocity(content, propertyReference, doc.getAuthorReference(), context); - } + return renderFileFromObjectProperty(object, "content", filename, doc, context); + } - // Prepare the response. - XWikiResponse response = context.getResponse(); - // Since object fields are read as unicode strings, the result does not depend on the wiki encoding. Force - // the output to UTF-8. - response.setCharacterEncoding(ENCODING); + /** + * Tries to serve the content of the property of an object as a skin file. + * + * @param object The object containing the content to serve + * @param propertyName The name of the property containing the content to serve + * @param filename The name of the skin file that should be rendered. + * @param doc The skin {@link XWikiDocument document}. + * @param context The current {@link XWikiContext request context}. + * @return true if the object exists, and the field is set to a non-empty value, and its content was + * successfully sent. + * @throws IOException If the response cannot be sent. + * + * @since 7.4.1 + */ + private boolean renderFileFromObjectProperty(BaseObject object, String propertyName, String filename, + XWikiDocument doc, + final XWikiContext context) throws IOException + { + // Get the content + String content = object.getStringValue(propertyName); + + if (StringUtils.isBlank(content)) { + // No content + LOGGER.debug("Object field empty"); + return false; + } + + XWiki xwiki = context.getWiki(); - // Write the content to the response's output stream. - byte[] data = content.getBytes(ENCODING); - setupHeaders(response, mimetype, doc.getDate(), data.length); - response.getOutputStream().write(data); + // Evaluate the file only if it's of a supported type. + String mimetype = xwiki.getEngineContext().getMimeType(filename.toLowerCase()); + if (isCssMimeType(mimetype) || isJavascriptMimeType(mimetype) || isLessCssFile(filename)) { + final ObjectPropertyReference propertyReference = + new ObjectPropertyReference(propertyName, object.getReference()); - return true; - } else { - LOGGER.debug("Object field not found or empty"); + // Evaluate the content with the rights of the document's author. + content = evaluateVelocity(content, propertyReference, doc.getAuthorReference(), context); } - return false; - } + // Prepare the response. + XWikiResponse response = context.getResponse(); + // Since object fields are read as unicode strings, the result does not depend on the wiki encoding. Force + // the output to UTF-8. + response.setCharacterEncoding(ENCODING); + // Write the content to the response's output stream. + byte[] data = content.getBytes(ENCODING); + setupHeaders(response, mimetype, doc.getDate(), data.length); + response.getOutputStream().write(data); + + return true; + } + private String evaluateVelocity(String content, EntityReference reference, DocumentReference author, XWikiContext context) {