<commit_before>/*******************************************************************************
 * Licensed to the Apache Software Foundation (ASF) under one
 * or more contributor license agreements.  See the NOTICE file
 * distributed with this work for additional information
 * regarding copyright ownership.  The ASF licenses this file
 * to you under the Apache License, Version 2.0 (the
 * "License"); you may not use this file except in compliance
 * with the License.  You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing,
 * software distributed under the License is distributed on an
 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
 * KIND, either express or implied.  See the License for the
 * specific language governing permissions and limitations
 * under the License.
 *******************************************************************************/
package org.ofbiz.product.category;

import java.io.IOException;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.ListIterator;
import java.util.Locale;

import javax.servlet.FilterChain;
import javax.servlet.RequestDispatcher;
import javax.servlet.ServletContext;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import javolution.util.FastList;

import org.ofbiz.base.component.ComponentConfig.WebappInfo;
import org.ofbiz.base.util.Debug;
import org.ofbiz.base.util.StringUtil;
import org.ofbiz.base.util.UtilHttp;
import org.ofbiz.base.util.StringUtil.StringWrapper;
import org.ofbiz.base.util.UtilValidate;
import org.ofbiz.common.UrlServletHelper;
import org.ofbiz.entity.Delegator;
import org.ofbiz.entity.GenericEntityException;
import org.ofbiz.entity.GenericValue;
import org.ofbiz.entity.condition.EntityCondition;
import org.ofbiz.entity.util.EntityQuery;
import org.ofbiz.entity.util.EntityUtil;
import org.ofbiz.product.catalog.CatalogWorker;
import org.ofbiz.product.category.CatalogUrlServlet.CatalogUrlBuilder;
import org.ofbiz.product.product.ProductContentWrapper;
import org.ofbiz.service.LocalDispatcher;
import org.ofbiz.webapp.OfbizUrlBuilder;
import org.ofbiz.webapp.WebAppUtil;
import org.ofbiz.webapp.control.ContextFilter;
import org.ofbiz.webapp.control.RequestHandler;
import org.ofbiz.webapp.control.RequestLinkUtil;
import org.ofbiz.webapp.control.WebAppConfigurationException;
import org.ofbiz.webapp.website.WebSiteWorker;
import org.xml.sax.SAXException;

/**
 * Catalog URL filter - processes requests generated by <code>@ofbizContentAltUrl</code>.
 * <p>
 * SCIPIO: FIXME?: There is a limitation in this filter that the trail will only be set to the product or category's
 * default category from the top catalog category. This defeat's Ofbiz's schema which allows a product or category
 * to have multiple parents. As a result, other similar calls have been restricted. See {@link #makeTrailElements}.
 */
public class CatalogUrlFilter extends ContextFilter {

    public final static String module = CatalogUrlFilter.class.getName();
    
    public static final String CONTROL_MOUNT_POINT = "control";
    public static final String PRODUCT_REQUEST = "product";
    public static final String CATEGORY_REQUEST = "category";
    
    protected static String defaultLocaleString = null;
    protected static String redirectUrl = null;
    
    @Override
    public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
        HttpServletRequest httpRequest = (HttpServletRequest) request;
        HttpServletResponse httpResponse = (HttpServletResponse) response;
        Delegator delegator = (Delegator) httpRequest.getSession().getServletContext().getAttribute("delegator");
        
        //Get ServletContext
        ServletContext servletContext = config.getServletContext();

        ContextFilter.setCharacterEncoding(request);

        //Set request attribute and session
        UrlServletHelper.setRequestAttributes(request, delegator, servletContext);
        
        // set initial parameters
        String initDefaultLocalesString = config.getInitParameter("defaultLocaleString");
        String initRedirectUrl = config.getInitParameter("redirectUrl");
        defaultLocaleString = UtilValidate.isNotEmpty(initDefaultLocalesString) ? initDefaultLocalesString : "";
        redirectUrl = UtilValidate.isNotEmpty(initRedirectUrl) ? initRedirectUrl : "";
        
        String pathInfo = httpRequest.getServletPath();
        if (UtilValidate.isNotEmpty(pathInfo)) {
            List<String> pathElements = StringUtil.split(pathInfo, "/");
            String alternativeUrl = pathElements.get(0);
            
            String productId = null;
            String productCategoryId = null;
            String urlContentId = null;
            try {
                // look for productId
                if (alternativeUrl.endsWith("-p")) {
                    productId = extractAltUrlProductId(delegator, alternativeUrl, "-p");
                }
                
                // look for productCategoryId
                if (alternativeUrl.endsWith("-c")) {
                    productCategoryId = extractAltUrlCategoryId(delegator, alternativeUrl, "-c");
                }

            } catch (GenericEntityException e) {
                Debug.logWarning("Cannot look for product and product category", module);
            }
            
            // SCIPIO: FIXME?: The code below also is only equivalent to makeDefaultCategoryTrailElements, 
            // which is it will only look up a default path under the top category, which is generally
            // not desirable but accepted for simple shops.
            
            // SCIPIO: get default category for product
            if (UtilValidate.isNotEmpty(productId) && UtilValidate.isEmpty(productCategoryId)) {
                // SCIPIO: factored out
                productCategoryId = getProductDefaultCategoryId(delegator, productId);
            }

            // SCIPIO: 2016-03-22: FIXME?: the getCatalogTopCategory call below 
            // is currently left unchanged, but note that because of it,
            // currently CatalogUrlFilter/ofbizCatalogAltUrl force browsing toward only the main top catalog category.
            // It does not allow browsing any other top categories (best-selling, promotions, etc.).
            // In some cases this is desirable, in others not.
            
            // generate trail belong to a top category
            // SCIPIO: 2017-08-15: this call is inappropriate; see method for details
            //String topCategoryId = CategoryWorker.getCatalogTopCategory(httpRequest, null);
            String topCategoryId = getCatalogTopCategory(httpRequest);
            List<GenericValue> trailCategories = CategoryWorker.getRelatedCategoriesRet(httpRequest, "trailCategories", topCategoryId, false, false, true);
            List<String> trailCategoryIds = EntityUtil.getFieldListFromEntityList(trailCategories, "productCategoryId", true);
            
            // look for productCategoryId from productId
            if (UtilValidate.isNotEmpty(productId)) {
                // SCIPIO: factored out
                String catId = getProductMatchingCategoryId(delegator, productId, trailCategoryIds);
                if (catId != null) {
                    productCategoryId = catId;
                }
            }

            // SCIPIO: 2016-03-22: FIXME?: The loop below was found to cause invalid category paths in SOLR addToSolr
            // (was very similar code) and had to be fixed there. I think there is a chance there may be bugs here as well,
            // but I'm not certain.
            
            // generate trail elements from productCategoryId
            if (UtilValidate.isNotEmpty(productCategoryId)) {
                // SCIPIO: 2017-11-07: factored out.
                getTrailElementsAndUpdateRequestAndTrail(httpRequest, delegator, productId, productCategoryId, trailCategoryIds, topCategoryId);
            }
            
            // SCIPIO: bumped this lower to simplify all code 
            // generate forward URL
            StringBuilder urlBuilder = new StringBuilder();
            urlBuilder.append(getControlServletPath(httpRequest));
            
            if (UtilValidate.isNotEmpty(productId)) {
                urlBuilder.append("/" + PRODUCT_REQUEST);
            } else {
                urlBuilder.append("/" + CATEGORY_REQUEST);
            }
            
            //Set view query parameters
            UrlServletHelper.setViewQueryParameters(request, urlBuilder);
            if (UtilValidate.isNotEmpty(productId) || UtilValidate.isNotEmpty(productCategoryId) || UtilValidate.isNotEmpty(urlContentId)) {
                Debug.logInfo("[Filtered request]: " + pathInfo + " (" + urlBuilder + ")", module);
                ContextFilter.setAttributesFromRequestBody(request);
                RequestDispatcher dispatch = request.getRequestDispatcher(urlBuilder.toString());
                dispatch.forward(request, response);
                return;
            }
            
            //Check path alias
            UrlServletHelper.checkPathAlias(request, httpResponse, delegator, pathInfo);
        }
        
        // we're done checking; continue on
        chain.doFilter(request, response);<commit_msg>NoRef/OFBIZ patch: CatalogUrlFilter: stock bugfixes + refactor for reuse (WARN: no longer resembles original stock code; structure could not be preserved; FIXME?: discovered unexpected operations applied on non-alt-url requests by the filter - implications unknown)<commit_after>/*******************************************************************************
 * Licensed to the Apache Software Foundation (ASF) under one
 * or more contributor license agreements.  See the NOTICE file
 * distributed with this work for additional information
 * regarding copyright ownership.  The ASF licenses this file
 * to you under the Apache License, Version 2.0 (the
 * "License"); you may not use this file except in compliance
 * with the License.  You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing,
 * software distributed under the License is distributed on an
 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
 * KIND, either express or implied.  See the License for the
 * specific language governing permissions and limitations
 * under the License.
 *******************************************************************************/
package org.ofbiz.product.category;

import java.io.IOException;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.ListIterator;
import java.util.Locale;

import javax.servlet.FilterChain;
import javax.servlet.RequestDispatcher;
import javax.servlet.ServletContext;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import javolution.util.FastList;

import org.ofbiz.base.component.ComponentConfig.WebappInfo;
import org.ofbiz.base.util.Debug;
import org.ofbiz.base.util.StringUtil;
import org.ofbiz.base.util.UtilHttp;
import org.ofbiz.base.util.StringUtil.StringWrapper;
import org.ofbiz.base.util.UtilValidate;
import org.ofbiz.common.UrlServletHelper;
import org.ofbiz.entity.Delegator;
import org.ofbiz.entity.GenericEntityException;
import org.ofbiz.entity.GenericValue;
import org.ofbiz.entity.condition.EntityCondition;
import org.ofbiz.entity.util.EntityQuery;
import org.ofbiz.entity.util.EntityUtil;
import org.ofbiz.product.catalog.CatalogWorker;
import org.ofbiz.product.category.CatalogUrlServlet.CatalogUrlBuilder;
import org.ofbiz.product.product.ProductContentWrapper;
import org.ofbiz.service.LocalDispatcher;
import org.ofbiz.webapp.OfbizUrlBuilder;
import org.ofbiz.webapp.WebAppUtil;
import org.ofbiz.webapp.control.ContextFilter;
import org.ofbiz.webapp.control.RequestHandler;
import org.ofbiz.webapp.control.RequestLinkUtil;
import org.ofbiz.webapp.control.WebAppConfigurationException;
import org.ofbiz.webapp.website.WebSiteWorker;
import org.xml.sax.SAXException;

/**
 * Catalog URL filter - processes requests generated by <code>@ofbizContentAltUrl</code>.
 * <p>
 * SCIPIO: FIXME?: There is a limitation in this filter that the trail will only be set to the product or category's
 * default category from the top catalog category. This defeat's Ofbiz's schema which allows a product or category
 * to have multiple parents. As a result, other similar calls have been restricted. See {@link #makeTrailElements}.
 */
public class CatalogUrlFilter extends ContextFilter {

    public final static String module = CatalogUrlFilter.class.getName();
    
    public static final String CONTROL_MOUNT_POINT = "control";
    public static final String PRODUCT_REQUEST = "product";
    public static final String CATEGORY_REQUEST = "category";
    
    protected static String defaultLocaleString = null;
    protected static String redirectUrl = null;
    
    @Override
    public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
        HttpServletRequest httpRequest = (HttpServletRequest) request;
        HttpServletResponse httpResponse = (HttpServletResponse) response;
        Delegator delegator = (Delegator) httpRequest.getSession().getServletContext().getAttribute("delegator");
        
        //Get ServletContext
        ServletContext servletContext = config.getServletContext();

        ContextFilter.setCharacterEncoding(request);

        //Set request attribute and session
        UrlServletHelper.setRequestAttributes(request, delegator, servletContext);
        
        // set initial parameters
        String initDefaultLocalesString = config.getInitParameter("defaultLocaleString");
        String initRedirectUrl = config.getInitParameter("redirectUrl");
        defaultLocaleString = UtilValidate.isNotEmpty(initDefaultLocalesString) ? initDefaultLocalesString : "";
        redirectUrl = UtilValidate.isNotEmpty(initRedirectUrl) ? initRedirectUrl : "";
        
        String pathInfo = httpRequest.getServletPath();
        if (UtilValidate.isNotEmpty(pathInfo)) {
            List<String> pathElements = StringUtil.split(pathInfo, "/");
            String alternativeUrl = pathElements.get(0);
            
            String productId = null;
            String productCategoryId = null;
            String urlContentId = null;
            try {
                if (alternativeUrl.endsWith("-p")) { // look for productId
                    productId = extractAltUrlProductId(delegator, alternativeUrl, "-p");
                } else if (alternativeUrl.endsWith("-c")) { // look for productCategoryId
                    productCategoryId = extractAltUrlCategoryId(delegator, alternativeUrl, "-c");
                }
            } catch (GenericEntityException e) {
                Debug.logWarning("Cannot look for product and product category: " + e.getMessage(), module);
            }
            
            // SCIPIO: 2017-11-07: this ID check was previously much further below, but has been moved here to lower the needless overhead
            if (UtilValidate.isNotEmpty(productId) || UtilValidate.isNotEmpty(productCategoryId) || UtilValidate.isNotEmpty(urlContentId)) {
            
                // SCIPIO: FIXME?: The code below also is only equivalent to makeDefaultCategoryTrailElements, 
                // which is it will only look up a default path under the top category, which is generally
                // not desirable but accepted for simple shops.
                
                // SCIPIO: get default category for product
                if (UtilValidate.isNotEmpty(productId) && UtilValidate.isEmpty(productCategoryId)) {
                    // SCIPIO: factored out
                    productCategoryId = getProductDefaultCategoryId(delegator, productId);
                }
    
                // SCIPIO: 2016-03-22: FIXME?: the getCatalogTopCategory call below 
                // is currently left unchanged, but note that because of it,
                // currently CatalogUrlFilter/ofbizCatalogAltUrl force browsing toward only the main top catalog category.
                // It does not allow browsing any other top categories (best-selling, promotions, etc.).
                // In some cases this is desirable, in others not.
                
                // generate trail belong to a top category
                // SCIPIO: 2017-08-15: this call is inappropriate; see method for details
                //String topCategoryId = CategoryWorker.getCatalogTopCategory(httpRequest, null);
                String topCategoryId = getCatalogTopCategory(httpRequest);
                List<GenericValue> trailCategories = CategoryWorker.getRelatedCategoriesRet(httpRequest, "trailCategories", topCategoryId, false, false, true);
                List<String> trailCategoryIds = EntityUtil.getFieldListFromEntityList(trailCategories, "productCategoryId", true);
                
                // look for productCategoryId from productId
                if (UtilValidate.isNotEmpty(productId)) {
                    // SCIPIO: factored out
                    String catId = getProductMatchingCategoryId(delegator, productId, trailCategoryIds);
                    if (catId != null) {
                        productCategoryId = catId;
                    }
                }
    
                // SCIPIO: 2016-03-22: FIXME?: The loop below was found to cause invalid category paths in SOLR addToSolr
                // (was very similar code) and had to be fixed there. I think there is a chance there may be bugs here as well,
                // but I'm not certain.
                
                // generate trail elements from productCategoryId
                if (UtilValidate.isNotEmpty(productCategoryId)) {
                    // SCIPIO: 2017-11-07: factored out.
                    getTrailElementsAndUpdateRequestAndTrail(httpRequest, delegator, productId, productCategoryId, trailCategoryIds, topCategoryId);
                }
                
                // SCIPIO: bumped this lower to simplify all code 
                // generate forward URL
                StringBuilder urlBuilder = new StringBuilder();
                urlBuilder.append(getControlServletPath(httpRequest));
                
                if (UtilValidate.isNotEmpty(productId)) {
                    urlBuilder.append("/" + PRODUCT_REQUEST);
                } else {
                    urlBuilder.append("/" + CATEGORY_REQUEST);
                }
                
                //Set view query parameters
                UrlServletHelper.setViewQueryParameters(request, urlBuilder);
                // SCIPIO: 2017-11-07: moved this check earlier to avoid large overhead on non-catalog calls
                //if (UtilValidate.isNotEmpty(productId) || UtilValidate.isNotEmpty(productCategoryId) || UtilValidate.isNotEmpty(urlContentId)) {
                Debug.logInfo("[Filtered request]: " + pathInfo + " (" + urlBuilder + ")", module);
                ContextFilter.setAttributesFromRequestBody(request);
                RequestDispatcher dispatch = request.getRequestDispatcher(urlBuilder.toString());
                dispatch.forward(request, response);
                return;
                //}
                
            } else {
                // SCIPIO: TODO/FIXME?: REVIEW: these calls were previously running even on non-alt-url requests;
                // as result, we can't remove them without testing to make sure no negative impacts
                // on rest of store... but highly dubious if they belong here...
                getCatalogTopCategory(httpRequest);
                UrlServletHelper.setViewQueryParameters(request, new StringBuilder());
            }
            
            //Check path alias
            UrlServletHelper.checkPathAlias(request, httpResponse, delegator, pathInfo);
        }
        
        // we're done checking; continue on
        chain.doFilter(request, response);
{'fraction_non_alphanumeric': 0.09238549061557912, 'fraction_numerical': 0.004376154818632695, 'mean_word_length': 2.773761467889908, 'pattern_counts': {'":': 0, '<': 15, '<?xml version=': 0, '>': 15, 'https://': 0, 'lorem ipsum': 0, 'www.': 2, 'xml': 2}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '680912', 'n_tokens_mistral': 5120, 'n_tokens_neox': 4882, 'n_words': 1462}