<commit_before>package org.broadinstitute.dsde.firecloud

import akka.actor.{ActorRefFactory, ActorSystem}
import akka.event.Logging.LogLevel
import akka.event.{Logging, LoggingAdapter}
import akka.http.scaladsl.marshallers.sprayjson.SprayJsonSupport._
import akka.http.scaladsl.model.{HttpEntity, HttpRequest, StatusCodes}
import akka.http.scaladsl.server
import akka.http.scaladsl.server.Directives._
import akka.http.scaladsl.server.RouteResult.Complete
import akka.http.scaladsl.server.directives.{DebuggingDirectives, LogEntry, LoggingMagnet}
import akka.http.scaladsl.server.{Directive, Directive0, ExceptionHandler, RouteResult}
import akka.stream.Materializer
import com.typesafe.scalalogging.LazyLogging
import org.broadinstitute.dsde.firecloud.model.{ModelSchema, UserInfo, WithAccessToken}
import org.broadinstitute.dsde.firecloud.service._
import org.broadinstitute.dsde.firecloud.utils.StandardUserInfoDirectives
import org.broadinstitute.dsde.firecloud.webservice._
import org.broadinstitute.dsde.rawls.model.{ErrorReport, ErrorReportSource}
import org.broadinstitute.dsde.workbench.oauth2.OpenIDConnectConfiguration
import org.slf4j.LoggerFactory

import scala.concurrent.ExecutionContext
import scala.language.postfixOps

object FireCloudApiService extends LazyLogging {

  val exceptionHandler = {

    import org.broadinstitute.dsde.rawls.model.WorkspaceJsonSupport._

    implicit val errorReportSource = ErrorReportSource("FireCloud") //TODO make sure this doesn't clobber source names globally

    ExceptionHandler {
      case withErrorReport: FireCloudExceptionWithErrorReport =>
        extractUri { uri =>
          extractMethod { method =>
            val statusCode = withErrorReport.errorReport.statusCode.getOrElse(StatusCodes.InternalServerError)
            if (statusCode.intValue / 100 == 5) {
              // mimic the log pattern from logRequests, below
              logger.error(s"${method} ${uri}: ${statusCode} error: ${withErrorReport.getMessage}")
            }
            complete(statusCode -> withErrorReport.errorReport)
          }
        }
      case e: Throwable =>
        // so we don't log the error twice when debug is enabled
        if (logger.underlying.isDebugEnabled) {
          logger.debug(e.getMessage, e)
        } else {
          logger.error(e.getMessage)
        }
        complete(StatusCodes.InternalServerError -> ErrorReport(e))
    }
  }
}

trait FireCloudApiService extends CookieAuthedApiService
  with EntityApiService
  with ExportEntitiesApiService
  with LibraryApiService
  with NamespaceApiService
  with NihApiService
  with OauthApiService
  with RegisterApiService
  with StorageApiService
  with WorkspaceApiService
  with NotificationsApiService
  with MethodConfigurationApiService
  with BillingApiService
  with SubmissionApiService
  with StatusApiService
  with MethodsApiService
  with Ga4ghApiService
  with UserApiService
  with ShareLogApiService
  with ManagedGroupApiService
  with CromIamApiService
  with HealthApiService
  with StaticNotebooksApiService
  with PerimeterApiService
{
<commit_msg>AJ-635: Remove stack traces exposed in HTTP error responses (#1060)<commit_after>package org.broadinstitute.dsde.firecloud

import akka.actor.{ActorRefFactory, ActorSystem}
import akka.event.Logging.LogLevel
import akka.event.{Logging, LoggingAdapter}
import akka.http.scaladsl.marshallers.sprayjson.SprayJsonSupport._
import akka.http.scaladsl.model.{HttpEntity, HttpRequest, StatusCodes}
import akka.http.scaladsl.server
import akka.http.scaladsl.server.Directives._
import akka.http.scaladsl.server.RouteResult.Complete
import akka.http.scaladsl.server.directives.{DebuggingDirectives, LogEntry, LoggingMagnet}
import akka.http.scaladsl.server.{Directive, Directive0, ExceptionHandler, RouteResult}
import akka.stream.Materializer
import com.typesafe.scalalogging.LazyLogging
import org.broadinstitute.dsde.firecloud.model.{ModelSchema, UserInfo, WithAccessToken}
import org.broadinstitute.dsde.firecloud.service._
import org.broadinstitute.dsde.firecloud.utils.StandardUserInfoDirectives
import org.broadinstitute.dsde.firecloud.webservice._
import org.broadinstitute.dsde.rawls.model.{ErrorReport, ErrorReportSource}
import org.broadinstitute.dsde.workbench.oauth2.OpenIDConnectConfiguration
import org.slf4j.LoggerFactory

import scala.concurrent.ExecutionContext
import scala.language.postfixOps

object FireCloudApiService extends LazyLogging {

  val exceptionHandler = {

    import org.broadinstitute.dsde.rawls.model.WorkspaceJsonSupport._

    implicit val errorReportSource = ErrorReportSource("FireCloud") //TODO make sure this doesn't clobber source names globally

    ExceptionHandler {
      case withErrorReport: FireCloudExceptionWithErrorReport =>
        extractUri { uri =>
          extractMethod { method =>
            val statusCode = withErrorReport.errorReport.statusCode.getOrElse(StatusCodes.InternalServerError)
            if (statusCode.intValue / 100 == 5) {
              // mimic the log pattern from logRequests, below
              logger.error(s"${method} ${uri}: ${statusCode} error: ${withErrorReport.getMessage}")
            }
            complete(statusCode -> withErrorReport.errorReport)
          }
        }
      case e: Throwable =>
        // so we don't log the error twice when debug is enabled
        if (logger.underlying.isDebugEnabled) {
          logger.debug(e.getMessage, e)
        } else {
          logger.error(e.toString)
        }
        // ErrorReport.apply with "message" kwarg. is specifically used to mute Stack Trace output in HTTP Error Responses
        complete(StatusCodes.InternalServerError -> ErrorReport(message=e.getMessage))
    }
  }
}

trait FireCloudApiService extends CookieAuthedApiService
  with EntityApiService
  with ExportEntitiesApiService
  with LibraryApiService
  with NamespaceApiService
  with NihApiService
  with OauthApiService
  with RegisterApiService
  with StorageApiService
  with WorkspaceApiService
  with NotificationsApiService
  with MethodConfigurationApiService
  with BillingApiService
  with SubmissionApiService
  with StatusApiService
  with MethodsApiService
  with Ga4ghApiService
  with UserApiService
  with ShareLogApiService
  with ManagedGroupApiService
  with CromIamApiService
  with HealthApiService
  with StaticNotebooksApiService
  with PerimeterApiService
{

{'fraction_non_alphanumeric': 0.0702660406885759, 'fraction_numerical': 0.0035993740219092333, 'mean_word_length': 4.330275229357798, 'pattern_counts': {'":': 0, '<': 3, '<?xml version=': 0, '>': 15, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, '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': '4156227', 'n_tokens_mistral': 1829, 'n_tokens_neox': 1799, 'n_words': 381}