1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34 package info.magnolia.cms.filters;
35
36 import info.magnolia.cms.beans.runtime.File;
37 import info.magnolia.cms.core.AggregationState;
38 import info.magnolia.cms.core.version.VersionManager;
39 import info.magnolia.cms.core.version.VersionedNode;
40 import info.magnolia.context.WebContext;
41 import info.magnolia.jcr.util.NodeNameHelper;
42 import info.magnolia.jcr.util.NodeTypes;
43 import info.magnolia.objectfactory.Components;
44
45 import java.io.IOException;
46
47 import javax.inject.Inject;
48 import javax.inject.Provider;
49 import javax.jcr.AccessDeniedException;
50 import javax.jcr.Node;
51 import javax.jcr.RepositoryException;
52 import javax.jcr.Session;
53 import javax.jcr.version.VersionException;
54 import javax.jcr.version.VersionHistory;
55 import javax.servlet.FilterChain;
56 import javax.servlet.ServletException;
57 import javax.servlet.http.HttpServletRequest;
58 import javax.servlet.http.HttpServletResponse;
59
60 import org.apache.commons.lang3.StringUtils;
61 import org.apache.jackrabbit.JcrConstants;
62 import org.slf4j.Logger;
63 import org.slf4j.LoggerFactory;
64
65
66
67
68
69 public class AggregatorFilter extends AbstractMgnlFilter {
70 private static final Logger log = LoggerFactory.getLogger(AggregatorFilter.class);
71
72 private final String VERSION_NUMBER = "mgnlVersion";
73
74 private final Provider<WebContext> contextProvider;
75
76 private final VersionManager versionManager;
77
78 private final NodeNameHelper nodeNameHelper;
79
80 @Inject
81 public AggregatorFilter(Provider<WebContext> contextProvider, VersionManager versionManager, NodeNameHelper nodeNameHelper) {
82 this.contextProvider = contextProvider;
83 this.versionManager = versionManager;
84 this.nodeNameHelper = nodeNameHelper;
85 }
86
87
88
89
90 @Deprecated
91 public AggregatorFilter(Provider<WebContext> contextProvider, VersionManager versionManager) {
92 this(contextProvider, versionManager, Components.getComponent(NodeNameHelper.class));
93 }
94
95
96
97
98 @Deprecated
99 public AggregatorFilter() {
100 this(() -> Components.getComponent(WebContext.class), Components.getComponent(VersionManager.class), Components.getComponent(NodeNameHelper.class));
101 }
102
103 @Override
104 public void doFilter(HttpServletRequest request, HttpServletResponse response, FilterChain chain) throws IOException, ServletException {
105
106 boolean success;
107 try {
108 success = collect();
109 } catch (AccessDeniedException e) {
110
111 log.debug(e.getMessage(), e);
112 if (!response.isCommitted()) {
113 response.setStatus(HttpServletResponse.SC_FORBIDDEN);
114 }
115
116 return;
117 } catch (RepositoryException e) {
118 log.error(e.getMessage(), e);
119 throw new ServletException(e.getMessage(), e);
120 }
121
122 if (!success) {
123 log.debug("Resource not found, redirecting request for [{}] to 404 URI", request.getRequestURI());
124
125 if (!response.isCommitted()) {
126 response.sendError(HttpServletResponse.SC_NOT_FOUND);
127 } else {
128 log.info("Unable to redirect to 404 page, response is already committed. URI was {}", request.getRequestURI());
129 }
130
131 return;
132 }
133 chain.doFilter(request, response);
134 }
135
136
137
138
139 protected boolean collect() throws RepositoryException {
140 final AggregationState aggregationState = contextProvider.get().getAggregationState();
141 final String handle = aggregationState.getHandle();
142 final String repository = aggregationState.getRepository();
143
144 final Session session = contextProvider.get().getJCRSession(repository);
145
146 Node requestedPage = null;
147 Node requestedData = null;
148 String templateName;
149
150 boolean nodeExists = nodeExistsInSession(session, handle);
151
152 if (nodeExists && !hasBinarySubnode(session, handle)) {
153 requestedPage = session.getNode(handle);
154
155
156 final String versionNumber = contextProvider.get().getAttribute(VERSION_NUMBER);
157 if (versionNumber != null) {
158 try {
159 VersionHistory versionHistory = versionManager.getVersionHistory(requestedPage);
160 if (versionHistory != null) {
161 requestedPage = new VersionedNode(versionHistory.getVersion(versionNumber), requestedPage);
162 }
163 } catch (VersionException e) {
164 log.warn("The version '{}' of the node '{}' doesn't exists, rendering current state.", versionNumber, requestedPage, e);
165 } catch (RepositoryException re) {
166 log.debug(re.getMessage(), re);
167 log.error("Unable to get versioned state {} of {}, rendering current state.", versionNumber, handle);
168 }
169 }
170
171 try {
172 templateName = NodeTypes.Renderable.getTemplate(requestedPage);
173 } catch (RepositoryException e) {
174 templateName = null;
175 }
176
177 if (StringUtils.isBlank(templateName)) {
178 log.error("No template configured for page [{}].", requestedPage);
179 }
180 } else {
181 if (nodeExists) {
182 requestedData = session.getNode(handle);
183 } else {
184
185 int lastIndexOfSlash = handle.lastIndexOf("/");
186
187 if (lastIndexOfSlash > 0) {
188
189 final String handleToUse = StringUtils.substringBeforeLast(handle, "/");
190
191 if (nodeExistsInSession(session, handleToUse)) {
192 requestedData = session.getNode(handleToUse);
193 aggregationState.setHandle(handleToUse);
194
195
196 } else {
197 log.debug("Couldn't access {}", handle);
198 return false;
199 }
200 }
201 }
202
203 if (requestedData != null) {
204 templateName = requestedData.hasProperty(File.PROPERTY_TEMPLATE) ? requestedData.getProperty(File.PROPERTY_TEMPLATE).getString() : StringUtils.EMPTY;
205 } else {
206 return false;
207 }
208 }
209
210
211 if (requestedPage != null) {
212 aggregationState.setMainContentNode(requestedPage);
213 aggregationState.setCurrentContentNode(requestedPage);
214 }
215 if (requestedData != null && isBinary(requestedData)) {
216 Fileruntime/File.html#File">File file = new File(requestedData);
217 aggregationState.setFile(file);
218 }
219
220 aggregationState.setTemplateName(templateName);
221
222 return true;
223 }
224
225 private boolean isBinary(Node requestedData) throws RepositoryException {
226 return requestedData.isNodeType(NodeTypes.Resource.NAME) ||
227 (requestedData.hasProperty("jcr:frozenPrimaryType") && requestedData.getProperty("jcr:frozenPrimaryType").getValue().getString().equals(NodeTypes.Resource.NAME));
228 }
229
230 private boolean hasBinarySubnode(Session session, String nodePath) throws RepositoryException {
231 return session.itemExists(nodePath + (nodePath.endsWith("/") ? "" : "/") + JcrConstants.JCR_DATA);
232 }
233
234
235
236
237
238
239
240 private boolean isJcrPathValid(String handle) {
241 if (StringUtils.isBlank(handle) || StringUtils.equals(handle, "/")) {
242
243 return false;
244 }
245
246 String[] jcrNames = handle.replaceFirst("/", "").split("/");
247
248 for (String jcrName : jcrNames) {
249 if (!nodeNameHelper.isValidName(jcrName)) {
250 return false;
251 }
252 }
253 return true;
254 }
255
256 private boolean nodeExistsInSession(Session session, String handle) throws RepositoryException {
257 return isJcrPathValid(handle) && session.nodeExists(handle);
258 }
259
260 }