FormsHandlingServlet.java 12.9 KB
/*
 * Decompiled with CFR 0_118.
 * 
 * Could not load the following classes:
 *  javax.servlet.Filter
 *  javax.servlet.FilterChain
 *  javax.servlet.FilterConfig
 *  javax.servlet.RequestDispatcher
 *  javax.servlet.Servlet
 *  javax.servlet.ServletException
 *  javax.servlet.ServletRequest
 *  javax.servlet.ServletResponse
 *  javax.servlet.http.HttpServletRequest
 *  org.apache.felix.scr.annotations.Component
 *  org.apache.felix.scr.annotations.Properties
 *  org.apache.felix.scr.annotations.Property
 *  org.apache.felix.scr.annotations.Reference
 *  org.apache.felix.scr.annotations.Service
 *  org.apache.sling.api.SlingHttpServletRequest
 *  org.apache.sling.api.SlingHttpServletResponse
 *  org.apache.sling.api.request.RequestDispatcherOptions
 *  org.apache.sling.api.request.RequestPathInfo
 *  org.apache.sling.api.resource.Resource
 *  org.apache.sling.api.resource.ResourceResolver
 *  org.apache.sling.api.resource.ResourceUtil
 *  org.apache.sling.api.resource.ResourceWrapper
 *  org.apache.sling.api.resource.ValueMap
 *  org.apache.sling.api.servlets.OptingServlet
 *  org.apache.sling.api.servlets.SlingAllMethodsServlet
 *  org.apache.sling.commons.osgi.OsgiUtil
 *  org.osgi.service.component.ComponentContext
 *  org.slf4j.Logger
 *  org.slf4j.LoggerFactory
 */
package com.day.cq.wcm.foundation.forms.impl;

import com.day.cq.wcm.foundation.forms.FieldHelper;
import com.day.cq.wcm.foundation.forms.FormsHelper;
import com.day.cq.wcm.foundation.forms.ValidationInfo;
import com.day.cq.wcm.foundation.forms.impl.FormsHandlingRequest;
import com.day.cq.wcm.foundation.forms.impl.FormsHandlingResponse;
import com.day.cq.wcm.foundation.forms.impl.RedirectRequest;
import com.day.cq.wcm.foundation.security.SaferSlingPostValidator;
import java.io.IOException;
import java.net.URI;
import java.net.URISyntaxException;
import java.util.Dictionary;
import java.util.Iterator;
import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.FilterConfig;
import javax.servlet.RequestDispatcher;
import javax.servlet.Servlet;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletRequest;
import org.apache.felix.scr.annotations.Component;
import org.apache.felix.scr.annotations.Properties;
import org.apache.felix.scr.annotations.Property;
import org.apache.felix.scr.annotations.Reference;
import org.apache.felix.scr.annotations.Service;
import org.apache.sling.api.SlingHttpServletRequest;
import org.apache.sling.api.SlingHttpServletResponse;
import org.apache.sling.api.request.RequestDispatcherOptions;
import org.apache.sling.api.request.RequestPathInfo;
import org.apache.sling.api.resource.Resource;
import org.apache.sling.api.resource.ResourceResolver;
import org.apache.sling.api.resource.ResourceUtil;
import org.apache.sling.api.resource.ResourceWrapper;
import org.apache.sling.api.resource.ValueMap;
import org.apache.sling.api.servlets.OptingServlet;
import org.apache.sling.api.servlets.SlingAllMethodsServlet;
import org.apache.sling.commons.osgi.OsgiUtil;
import org.osgi.service.component.ComponentContext;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

@Component(metatype=1, label="Adobe CQ Form Handling Servlet", description="Accepts posting to a form start component and performs validations")
@Service(value={Servlet.class, Filter.class})
@Properties(value={@Property(name="sling.servlet.resourceTypes", value={"foundation/components/form/start"}, propertyPrivate=1), @Property(name="sling.servlet.methods", value={"POST"}, propertyPrivate=1), @Property(name="sling.servlet.selectors", value={"form"}, propertyPrivate=1), @Property(name="filter.scope", value={"request"}, propertyPrivate=1), @Property(name="filter.order", intValue={-600}, propertyPrivate=1), @Property(name="service.description", value={"Form Handling Servlet"})})
public class FormsHandlingServlet
extends SlingAllMethodsServlet
implements OptingServlet,
Filter {
    protected static final String EXTENSION = "html";
    protected static final String SELECTOR = "form";
    protected static final String ATTR_RESOURCE = FormsHandlingServlet.class.getName() + "/resource";
    protected final Logger logger;
    @Property(value={}, label="Parameter Name Whitelist", description="List of name expressions that will pass request validation. A validation error will occur if any posted parameters are not in the whitelist and not defined on the form.")
    private static final String DATA_NAME_WHITELIST = "name.whitelist";
    private String[] dataNameWhitelist;
    @Property(boolValue={1}, label="Allow Expressions", description="Evaluate expressions on form submissions.")
    public static final String ALLOW_EXPRESSIONS = "allow.expressions";
    private boolean allowExpressions;
    @Reference
    private SaferSlingPostValidator validator;

    public FormsHandlingServlet() {
        this.logger = LoggerFactory.getLogger(this.getClass());
    }

    protected void activate(ComponentContext componentContext) {
        Dictionary properties = componentContext.getProperties();
        this.dataNameWhitelist = OsgiUtil.toStringArray(properties.get("name.whitelist"));
        this.allowExpressions = (Boolean)properties.get("allow.expressions");
    }

    public boolean accepts(SlingHttpServletRequest request) {
        return "html".equals(request.getRequestPathInfo().getExtension());
    }

    protected void doPost(SlingHttpServletRequest request, SlingHttpServletResponse response) throws ServletException, IOException {
        ValidationInfo info;
        String actionType;
        if (this.validator.reject((SlingHttpServletRequest)request, this.dataNameWhitelist)) {
            response.sendError(400);
            return;
        }
        if (ResourceUtil.isNonExistingResource((Resource)request.getResource()) || request.getAttribute(ATTR_RESOURCE) == null) {
            this.logger.debug("Received fake request!");
            response.setStatus(500);
            return;
        }
        if (this.logger.isDebugEnabled()) {
            this.logger.debug("Validating POST request with form definition stored at {}.", (Object)request.getResource().getPath());
        }
        FormsHandlingRequest formsRequest = new FormsHandlingRequest((SlingHttpServletRequest)request);
        FormsHandlingResponse formsResponse = new FormsHandlingResponse(response);
        request.setAttribute("cq.form.expressions.enabled", (Object)this.allowExpressions);
        Resource formResource = request.getResource();
        FormsHelper.getFormId((SlingHttpServletRequest)request);
        this.validate((SlingHttpServletRequest)formsRequest, (SlingHttpServletResponse)formsResponse, formResource);
        ValueMap properties = ResourceUtil.getValueMap((Resource)formResource);
        String string = actionType = properties == null ? "" : (String)properties.get("actionType", (Object)"");
        if (actionType.length() == 0) {
            info = ValidationInfo.createValidationInfo((SlingHttpServletRequest)request);
            info.addErrorMessage(null, "Unable to process the form: missing actionType");
        } else {
            request.setAttribute("cq.form.prop.whitelist", (Object)this.dataNameWhitelist);
            FormsHelper.runAction(actionType, "formservervalidation", formResource, (SlingHttpServletRequest)formsRequest, (SlingHttpServletResponse)formsResponse);
            info = ValidationInfo.getValidationInfo((HttpServletRequest)request);
        }
        if (info != null) {
            this.logger.debug("Form {} is not valid: {}", (Object)formResource.getPath(), (Object)info);
            Resource rsrc = (Resource)request.getAttribute(ATTR_RESOURCE);
            request.removeAttribute(ATTR_RESOURCE);
            request.getRequestDispatcher(rsrc).forward((ServletRequest)formsRequest, (ServletResponse)response);
            return;
        }
        FormsHelper.runAction(actionType, "forward", formResource, (SlingHttpServletRequest)formsRequest, (SlingHttpServletResponse)formsResponse);
        String forwardPath = FormsHelper.getForwardPath((SlingHttpServletRequest)request);
        if (forwardPath != null && forwardPath.length() > 0) {
            String redirect;
            if (FormsHelper.isRedirectToReferrer((ServletRequest)request) && request.getParameter(":redirect") == null) {
                String referrerPath = this.getReferrerPath((SlingHttpServletRequest)request);
                request = new RedirectRequest((SlingHttpServletRequest)request, referrerPath);
            }
            if ((redirect = FormsHelper.getForwardRedirect((ServletRequest)request)) != null) {
                request = new RedirectRequest((SlingHttpServletRequest)request, redirect);
            }
            if (forwardPath.endsWith("/")) {
                forwardPath = forwardPath + '*';
            }
            Resource forwardResource = request.getResourceResolver().resolve(forwardPath);
            request.getRequestDispatcher(forwardResource, FormsHelper.getForwardOptions((ServletRequest)request)).forward((ServletRequest)request, (ServletResponse)response);
            FormsHelper.runAction(actionType, "cleanup", formResource, (SlingHttpServletRequest)formsRequest, (SlingHttpServletResponse)formsResponse);
            return;
        }
        FormsHelper.runAction(actionType, "post", formResource, (SlingHttpServletRequest)request, response);
    }

    private String getReferrerPath(SlingHttpServletRequest request) {
        String referrerPath;
        String referrer = FormsHelper.getReferrer((HttpServletRequest)request);
        try {
            URI referrerUri = new URI(referrer);
            referrerPath = referrerUri.getPath();
        }
        catch (URISyntaxException e) {
            this.logger.warn("given redirect target ({}) is not a valid uri: {}", (Object)referrer, (Object)e);
            return null;
        }
        return referrerPath;
    }

    private ValidationInfo validate(SlingHttpServletRequest request, SlingHttpServletResponse response, final Resource formResource) throws ServletException, IOException {
        Iterator<Resource> iter = FormsHelper.getFormElements(formResource);
        while (iter.hasNext()) {
            Resource formField = iter.next();
            FieldHelper.initializeField(request, response, formField);
            FormsHelper.includeResource(request, response, formField, "servervalidation");
        }
        ValueMap properties = ResourceUtil.getValueMap((Resource)formResource);
        final String valScriptRT = (String)properties.get("validationRT", (Object)formResource.getResourceType());
        if (valScriptRT != null && valScriptRT.length() > 0) {
            Object valScriptResource = formResource;
            if (!formResource.getResourceType().equals(valScriptRT)) {
                valScriptResource = new ResourceWrapper(formResource){

                    public String getResourceType() {
                        return valScriptRT;
                    }

                    public String getResourceSuperType() {
                        return formResource.getResourceType();
                    }
                };
            }
            FormsHelper.includeResource(request, response, (Resource)valScriptResource, "formservervalidation");
        }
        return ValidationInfo.getValidationInfo((HttpServletRequest)request);
    }

    public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
        SlingHttpServletRequest req;
        if (request instanceof SlingHttpServletRequest && "POST".equalsIgnoreCase((req = (SlingHttpServletRequest)request).getMethod()) && req.getParameter(":formstart") != null) {
            String formPath = req.getParameter(":formstart");
            Resource formResource = ((SlingHttpServletRequest)request).getResourceResolver().getResource(formPath);
            if (formResource != null && ResourceUtil.isA((Resource)formResource, (String)"foundation/components/form/start")) {
                req.setAttribute(ATTR_RESOURCE, (Object)req.getResource());
                StringBuilder sb = new StringBuilder();
                if (!formPath.startsWith("/")) {
                    sb.append(req.getResource().getPath());
                    sb.append('/');
                }
                sb.append(formPath);
                sb.append('.');
                sb.append("form");
                sb.append('.');
                sb.append("html");
                String forwardPath = sb.toString();
                req.getRequestDispatcher(forwardPath).forward(request, response);
                return;
            }
        }
        chain.doFilter(request, response);
    }

    public void init(FilterConfig config) throws ServletException {
    }

    protected void bindValidator(SaferSlingPostValidator saferSlingPostValidator) {
        this.validator = saferSlingPostValidator;
    }

    protected void unbindValidator(SaferSlingPostValidator saferSlingPostValidator) {
        if (this.validator == saferSlingPostValidator) {
            this.validator = null;
        }
    }

}