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