001: /*
002: * Licensed to the Apache Software Foundation (ASF) under one or more
003: * contributor license agreements. See the NOTICE file distributed with
004: * this work for additional information regarding copyright ownership.
005: * The ASF licenses this file to You under the Apache License, Version 2.0
006: * (the "License"); you may not use this file except in compliance with
007: * the License. You may obtain a copy of the License at
008: *
009: * http://www.apache.org/licenses/LICENSE-2.0
010: *
011: * Unless required by applicable law or agreed to in writing, software
012: * distributed under the License is distributed on an "AS IS" BASIS,
013: * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
014: * See the License for the specific language governing permissions and
015: * limitations under the License.
016: */
017: package org.apache.wicket.protocol.http;
018:
019: import javax.servlet.http.HttpServletResponse;
020:
021: import org.apache.wicket.AccessStackPageMap;
022: import org.apache.wicket.Application;
023: import org.apache.wicket.Component;
024: import org.apache.wicket.IPageMap;
025: import org.apache.wicket.IRequestTarget;
026: import org.apache.wicket.Page;
027: import org.apache.wicket.RequestCycle;
028: import org.apache.wicket.Session;
029: import org.apache.wicket.AccessStackPageMap.Access;
030: import org.apache.wicket.protocol.http.request.WebRequestCodingStrategy;
031: import org.apache.wicket.protocol.http.servlet.AbortWithWebErrorCodeException;
032: import org.apache.wicket.request.AbstractRequestCycleProcessor;
033: import org.apache.wicket.request.IRequestCodingStrategy;
034: import org.apache.wicket.request.RequestParameters;
035: import org.apache.wicket.request.target.basic.EmptyAjaxRequestTarget;
036: import org.apache.wicket.util.string.Strings;
037: import org.slf4j.Logger;
038: import org.slf4j.LoggerFactory;
039:
040: /**
041: * Default request processor implementation for normal web applications.
042: *
043: * @author eelcohillenius
044: */
045: public class WebRequestCycleProcessor extends
046: AbstractRequestCycleProcessor {
047: private static final Logger log = LoggerFactory
048: .getLogger(WebRequestCycleProcessor.class);
049:
050: /**
051: * Construct.
052: */
053: public WebRequestCycleProcessor() {
054: }
055:
056: /**
057: * @see org.apache.wicket.request.IRequestCycleProcessor#resolve(org.apache.wicket.RequestCycle,
058: * org.apache.wicket.request.RequestParameters)
059: */
060: public IRequestTarget resolve(final RequestCycle requestCycle,
061: final RequestParameters requestParameters) {
062: IRequestCodingStrategy requestCodingStrategy = requestCycle
063: .getProcessor().getRequestCodingStrategy();
064:
065: final String path = requestParameters.getPath();
066: IRequestTarget target = null;
067:
068: // See whether this request points to a bookmarkable page
069: if (requestParameters.getBookmarkablePageClass() != null) {
070: target = resolveBookmarkablePage(requestCycle,
071: requestParameters);
072: }
073: // See whether this request points to a rendered page
074: else if (requestParameters.getComponentPath() != null) {
075: // marks whether or not we will be processing this request
076: boolean processRequest = true;
077: synchronized (requestCycle.getSession()) {
078: // we need to check if this request has been flagged as
079: // process-only-if-path-is-active and if so make sure this
080: // condition is met
081: if (requestParameters.isOnlyProcessIfPathActive()) {
082: // this request has indeed been flagged as
083: // process-only-if-path-is-active
084:
085: Session session = Session.get();
086: IPageMap pageMap = session.pageMapForName(
087: requestParameters.getPageMapName(), false);
088: if (pageMap == null) {
089: // requested pagemap no longer exists - ignore this
090: // request
091: processRequest = false;
092: } else if (pageMap instanceof AccessStackPageMap) {
093: AccessStackPageMap accessStackPageMap = (AccessStackPageMap) pageMap;
094: if (accessStackPageMap.getAccessStack().size() > 0) {
095: final Access access = (Access) accessStackPageMap
096: .getAccessStack().peek();
097:
098: final int pageId = Integer
099: .parseInt(Strings
100: .firstPathComponent(
101: requestParameters
102: .getComponentPath(),
103: Component.PATH_SEPARATOR));
104:
105: if (pageId != access.getId()) {
106: // the page is no longer the active page
107: // - ignore this request
108: processRequest = false;
109: } else {
110: final int version = requestParameters
111: .getVersionNumber();
112: if (version != Page.LATEST_VERSION
113: && version != access
114: .getVersion()) {
115: // version is no longer the active version -
116: // ignore this request
117: processRequest = false;
118: }
119: }
120: }
121: } else {
122: // TODO also this should work..
123: }
124: }
125: }
126: if (processRequest) {
127: try {
128: target = resolveRenderedPage(requestCycle,
129: requestParameters);
130: } catch (IgnoreAjaxRequestException e) {
131: target = EmptyAjaxRequestTarget.getInstance();
132: }
133: } else {
134: throw new PageExpiredException(
135: "Request cannot be processed");
136: }
137: }
138: // See whether this request points to a shared resource
139: else if (requestParameters.getResourceKey() != null) {
140: target = resolveSharedResource(requestCycle,
141: requestParameters);
142: }
143: // See whether this request points to the home page
144: else if (Strings.isEmpty(path) || ("/".equals(path))) {
145: target = resolveHomePageTarget(requestCycle,
146: requestParameters);
147: }
148:
149: // NOTE we are doing the mount check as the last item, so that it will
150: // only be executed when everything else fails. This enables URLs like
151: // /foo/bar/?wicket:bookmarkablePage=my.Page to be resolved, where
152: // is either a valid mount or a non-valid mount. I (Eelco) am not
153: // absolutely sure this is a great way to go, but it seems to have been
154: // established as the default way of doing things. If we ever want to
155: // tighten the algorithm up, it should be combined by going back to
156: // mountless paths so that requests with Wicket parameters like
157: // 'bookmarkablePage' are always created and resolved in the same
158: // fashion. There is a test for this in UrlMountingTest.
159: if (target == null) {
160: // still null? check for a mount
161: target = requestCodingStrategy
162: .targetForRequest(requestParameters);
163: } else {
164: // a target was found, but not by looking up a mount. check whether
165: // this is allowed
166: if (Application.get().getSecuritySettings()
167: .getEnforceMounts()
168: && requestCodingStrategy.pathForTarget(target) != null) {
169: String msg = "Direct access not allowed for mounted targets";
170: // the target was mounted, but we got here via another path
171: // : deny the request
172: log.error(msg + " [request="
173: + requestCycle.getRequest() + ",target="
174: + target + ",session=" + Session.get() + "]");
175: throw new AbortWithWebErrorCodeException(
176: HttpServletResponse.SC_FORBIDDEN, msg);
177: }
178: }
179:
180: if (target == null) {
181: // if we get here, we have no regconized Wicket target, and thus
182: // regard this as a external (non-wicket) resource request on
183: // this server
184: return resolveExternalResource(requestCycle);
185: }
186:
187: return target;
188: }
189:
190: /**
191: * @see org.apache.wicket.request.AbstractRequestCycleProcessor#newRequestCodingStrategy()
192: */
193: protected IRequestCodingStrategy newRequestCodingStrategy() {
194: return new WebRequestCodingStrategy();
195: }
196: }
|