<commit_before>/**
 * Copyright (C) 2010 Orbeon, Inc.
 *
 * This program is free software; you can redistribute it and/or modify it under the terms of the
 * GNU Lesser General Public License as published by the Free Software Foundation; either version
 * 2.1 of the License, or (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
 * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
 * See the GNU Lesser General Public License for more details.
 *
 * The full text of the license is available at http://www.gnu.org/copyleft/lesser.html
 */
package org.orbeon.oxf.servlet

import java.io._
import java.util._
import javax.servlet._
import javax.servlet.http._

import org.apache.commons.lang3.StringUtils
import org.orbeon.oxf.common.Defaults
import org.orbeon.oxf.util.IOUtils._
import org.orbeon.oxf.util.NetUtils
import org.orbeon.oxf.util.PathUtils._

private case class FilterSettings(context: ServletContext, orbeonContextPathOpt: Option[String], defaultEncoding: String) {
  // NOTE: Never match anything if there is no context path
  val OrbeonResourceRegex = orbeonContextPathOpt map (path ⇒ s"$path(/.*)".r) getOrElse "$.".r
}

// This filter allows forwarding requests from your web app to an separate Orbeon Forms context.
class OrbeonXFormsFilter extends Filter {

  import org.orbeon.oxf.servlet.OrbeonXFormsFilter._

  private var settingsOpt: Option[FilterSettings] = None

  def init(filterConfig: FilterConfig): Unit =
    settingsOpt =
      Some(
        FilterSettings(
          filterConfig.getServletContext,
          Option(filterConfig.getInitParameter(RendererContextParameterName)) map normalizeContextPath,
          Option(filterConfig.getInitParameter(DefaultEncodingParameterName)) getOrElse Defaults.DefaultEncodingForServletCompatibility
        )
      )

  def destroy(): Unit = settingsOpt = None

  def doFilter(servletRequest: ServletRequest, servletResponse: ServletResponse, filterChain: FilterChain) =
    settingsOpt foreach {
      case settings @ FilterSettings(servletContext, orbeonContextPathOpt, defaultEncoding) ⇒

        val orbeonContext = (
          orbeonContextPathOpt
          map { orbeonContextPath ⇒
            servletContext.getContext(orbeonContextPath) ensuring (
              _ ne null,
              s"Can't find Orbeon Forms context called '$orbeonContextPath'. Check the " +
              s"'$RendererContextParameterName' filter initialization parameter and the " +
              s"<Context crossContext='true'/> attribute."
            )
          }
          getOrElse servletContext
        )

        def getOrbeonDispatcher(path: String) =
          orbeonContext.getRequestDispatcher(path) ensuring
          (_ ne null, "Can't find Orbeon Forms request dispatcher.")

        val httpRequest  = servletRequest.asInstanceOf[HttpServletRequest]
        val httpResponse = servletResponse.asInstanceOf[HttpServletResponse]
        val requestPath  = NetUtils.getRequestPathInfo(httpRequest)

        // Set whether deployment is integrated or separate
        // NOTE: Also for resources so that e.g. /xforms-server, /xforms-server-submit can handle URLs properly.
        httpRequest.setAttribute(
          RendererDeploymentAttributeName,
          if (orbeonContext eq servletContext) "integrated" else "separate"
        )

        requestPath match {
          case settings.OrbeonResourceRegex(subRequestPath) ⇒
            // Directly forward all requests meant for Orbeon Forms resources (including /xforms-server)

            // Check that the session exists for any request to /xforms-server
            // The purpose of this check is that if the application has invalidated the session, we don't
            // want to allow further interactions with a page.
            // NOTE: With Tomcat this doesn't seem necessary. Other containers might work differently.
            if (subRequestPath.startsWith("/xforms-server"))
              httpRequest.getSession(false) ensuring
              (_ ne null, "Session has expired. Unable to process incoming request.")

            getOrbeonDispatcher(subRequestPath).forward(httpRequest, httpResponse)
          case _ ⇒
            // Forward the request to the Orbeon Forms renderer
            val requestWrapper  = new FilterRequestWrapper(httpRequest)
            val responseWrapper = new FilterResponseWrapper(httpResponse, defaultEncoding)

            // Execute filter
            filterChain.doFilter(requestWrapper, responseWrapper)

            // Restore content length if needed, see https://github.com/orbeon/orbeon-forms/issues/2775
            httpResponse.setContentLength(-1)

            val failureCodeOpt =
              responseWrapper.statusCode filterNot NetUtils.isSuccessCode

            failureCodeOpt match {
              case None ⇒
                // Content can be a String or other content set as a request attribute which can be read by the
                // scope generator
                val content =
                  Option(httpRequest.getAttribute(RendererDocumentAttributeName)) orElse
                  responseWrapper.content

                val nonEmptyContent = content match {
                  case Some(s: String) ⇒ StringUtils.isNotBlank(s)
                  case Some(_)         ⇒ true
                  case None            ⇒ false
                }

                // Forward to Orbeon Forms for rendering only if there is content to be rendered, otherwise just
                // return and let the filterChain finish its life naturally, assuming that when sendRedirect is
                // used, no content is available in the response object.
                if (nonEmptyContent) {

                  // Make sure document is set when available
                  content foreach {
                    httpRequest.setAttribute(
                      RendererDocumentAttributeName,
                      _
                    )
                  }

                  // Whether there is a session
                  httpRequest.setAttribute(
                    RendererHasSessionAttributeName,
                    (httpRequest.getSession(false) ne null).toString
                  )

                  // Mediatype if available<commit_msg>Use our own StringUtils<commit_after>/**
 * Copyright (C) 2010 Orbeon, Inc.
 *
 * This program is free software; you can redistribute it and/or modify it under the terms of the
 * GNU Lesser General Public License as published by the Free Software Foundation; either version
 * 2.1 of the License, or (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
 * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
 * See the GNU Lesser General Public License for more details.
 *
 * The full text of the license is available at http://www.gnu.org/copyleft/lesser.html
 */
package org.orbeon.oxf.servlet

import java.io._
import java.util._
import javax.servlet._
import javax.servlet.http._

import org.orbeon.oxf.common.Defaults
import org.orbeon.oxf.util.IOUtils._
import org.orbeon.oxf.util.NetUtils
import org.orbeon.oxf.util.PathUtils._
import org.orbeon.oxf.util.StringUtils._

private case class FilterSettings(context: ServletContext, orbeonContextPathOpt: Option[String], defaultEncoding: String) {
  // NOTE: Never match anything if there is no context path
  val OrbeonResourceRegex = orbeonContextPathOpt map (path ⇒ s"$path(/.*)".r) getOrElse "$.".r
}

// This filter allows forwarding requests from your web app to an separate Orbeon Forms context.
class OrbeonXFormsFilter extends Filter {

  import org.orbeon.oxf.servlet.OrbeonXFormsFilter._

  private var settingsOpt: Option[FilterSettings] = None

  def init(filterConfig: FilterConfig): Unit =
    settingsOpt =
      Some(
        FilterSettings(
          filterConfig.getServletContext,
          Option(filterConfig.getInitParameter(RendererContextParameterName)) map normalizeContextPath,
          Option(filterConfig.getInitParameter(DefaultEncodingParameterName)) getOrElse Defaults.DefaultEncodingForServletCompatibility
        )
      )

  def destroy(): Unit = settingsOpt = None

  def doFilter(servletRequest: ServletRequest, servletResponse: ServletResponse, filterChain: FilterChain) =
    settingsOpt foreach {
      case settings @ FilterSettings(servletContext, orbeonContextPathOpt, defaultEncoding) ⇒

        val orbeonContext = (
          orbeonContextPathOpt
          map { orbeonContextPath ⇒
            servletContext.getContext(orbeonContextPath) ensuring (
              _ ne null,
              s"Can't find Orbeon Forms context called '$orbeonContextPath'. Check the " +
              s"'$RendererContextParameterName' filter initialization parameter and the " +
              s"<Context crossContext='true'/> attribute."
            )
          }
          getOrElse servletContext
        )

        def getOrbeonDispatcher(path: String) =
          orbeonContext.getRequestDispatcher(path) ensuring
          (_ ne null, "Can't find Orbeon Forms request dispatcher.")

        val httpRequest  = servletRequest.asInstanceOf[HttpServletRequest]
        val httpResponse = servletResponse.asInstanceOf[HttpServletResponse]
        val requestPath  = NetUtils.getRequestPathInfo(httpRequest)

        // Set whether deployment is integrated or separate
        // NOTE: Also for resources so that e.g. /xforms-server, /xforms-server-submit can handle URLs properly.
        httpRequest.setAttribute(
          RendererDeploymentAttributeName,
          if (orbeonContext eq servletContext) "integrated" else "separate"
        )

        requestPath match {
          case settings.OrbeonResourceRegex(subRequestPath) ⇒
            // Directly forward all requests meant for Orbeon Forms resources (including /xforms-server)

            // Check that the session exists for any request to /xforms-server
            // The purpose of this check is that if the application has invalidated the session, we don't
            // want to allow further interactions with a page.
            // NOTE: With Tomcat this doesn't seem necessary. Other containers might work differently.
            if (subRequestPath.startsWith("/xforms-server"))
              httpRequest.getSession(false) ensuring
              (_ ne null, "Session has expired. Unable to process incoming request.")

            getOrbeonDispatcher(subRequestPath).forward(httpRequest, httpResponse)
          case _ ⇒
            // Forward the request to the Orbeon Forms renderer
            val requestWrapper  = new FilterRequestWrapper(httpRequest)
            val responseWrapper = new FilterResponseWrapper(httpResponse, defaultEncoding)

            // Execute filter
            filterChain.doFilter(requestWrapper, responseWrapper)

            // Restore content length if needed, see https://github.com/orbeon/orbeon-forms/issues/2775
            httpResponse.setContentLength(-1)

            val failureCodeOpt =
              responseWrapper.statusCode filterNot NetUtils.isSuccessCode

            failureCodeOpt match {
              case None ⇒
                // Content can be a String or other content set as a request attribute which can be read by the
                // scope generator
                val content =
                  Option(httpRequest.getAttribute(RendererDocumentAttributeName)) orElse
                  responseWrapper.content

                val nonEmptyContent = content match {
                  case Some(s: String) ⇒ s.nonBlank
                  case Some(_)         ⇒ true
                  case None            ⇒ false
                }

                // Forward to Orbeon Forms for rendering only if there is content to be rendered, otherwise just
                // return and let the filterChain finish its life naturally, assuming that when sendRedirect is
                // used, no content is available in the response object.
                if (nonEmptyContent) {

                  // Make sure document is set when available
                  content foreach {
                    httpRequest.setAttribute(
                      RendererDocumentAttributeName,
                      _
                    )
                  }

                  // Whether there is a session
                  httpRequest.setAttribute(
                    RendererHasSessionAttributeName,
                    (httpRequest.getSession(false) ne null).toString
                  )

                  // Mediatype if available
{'fraction_non_alphanumeric': 0.06305100755667506, 'fraction_numerical': 0.0018104534005037784, 'mean_word_length': 2.346062681063998, 'pattern_counts': {'":': 0, '<': 5, '<?xml version=': 0, '>': 5, 'https://': 2, 'lorem ipsum': 0, 'www.': 2, 'xml': 0}, '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': '3138903', 'n_tokens_mistral': 3123, 'n_tokens_neox': 2992, 'n_words': 1028}