guardian / play-brotli-filter Goto Github PK
View Code? Open in Web Editor NEWBrotli filter for the playframework
License: Apache License 2.0
Brotli filter for the playframework
License: Apache License 2.0
This is a weird one and I'm pretty sure it's actually a bug with the IntelliJ Scala plugin (raised as https://youtrack.jetbrains.com/issue/SCL-22833/Error-compiling-in-IntelliJ-with-play-brotli-filter-dependency-on-Scala-3.4), but thought I would raise here in case it rings any bells. On any project that uses this library as a dependency, it will fail to compile on IntelliJ using Scala 3.4.0 or later if there is any use of implicits in the project.
Minimal reproduction case: https://github.com/matmannion/scala-3.4-play-brotli-filter-ij
It still compiles fine with sbt compile
, but using the IntelliJ compiler it throws an error:
Executing pre-compile tasks…
Running 'before' tasks
Checking sources
Searching for compilable files... [tests of root]
Checking dependencies… [root]
Dependency analysis found 0 affected files
Updating dependency information… [root]
Searching for compilable files... [root]
Reading compilation settings... [root]
Compiling... [root]
scala: compiling 1 Scala source to /Users/mat/code/test/target/scala-3.4.2/classes ...
scala:
unhandled exception while running MegaPhase{protectedAccessors, extmethods, uncacheGivenAliases, checkStatic, elimByName, hoistSuperArgs, forwardDepChecks, specializeApplyMethods, tryCatchPatterns, patternMatcher} on /Users/mat/code/test/src/main/scala/Test.scala
An unhandled exception was thrown in the compiler.
Please file a crash report here:
https://github.com/scala/scala3/issues/new/choose
For non-enriched exceptions, compile with -Yno-enrich-error-messages.
while compiling: /Users/mat/code/test/src/main/scala/Test.scala
during phase: MegaPhase{protectedAccessors, extmethods, uncacheGivenAliases, checkStatic, elimByName, hoistSuperArgs, forwardDepChecks, specializeApplyMethods, tryCatchPatterns, patternMatcher}
mode: Mode(ImplicitsEnabled)
library version: version 2.13.12
compiler version: version 3.4.2
settings: -classpath /Users/mat/code/test/target/scala-3.4.2/classes:/Users/mat/Library/Caches/Coursier/v1/https/repo1.maven.org/maven2/com/aayushatharva/brotli4j/brotli4j/1.16.0/brotli4j-1.16.0.jar:/Users/mat/Library/Caches/Coursier/v1/https/repo1.maven.org/maven2/com/aayushatharva/brotli4j/native-osx-aarch64/1.16.0/native-osx-aarch64-1.16.0.jar:/Users/mat/Library/Caches/Coursier/v1/https/repo1.maven.org/maven2/com/aayushatharva/brotli4j/service/1.16.0/service-1.16.0.jar:/Users/mat/Library/Caches/Coursier/v1/https/repo1.maven.org/maven2/com/gu/brotli4s_3/0.16.1/brotli4s_3-0.16.1.jar:/Users/mat/Library/Caches/Coursier/v1/https/repo1.maven.org/maven2/com/gu/pekko-stream-brotli_3/0.16.1/pekko-stream-brotli_3-0.16.1.jar:/Users/mat/Library/Caches/Coursier/v1/https/repo1.maven.org/maven2/com/gu/play-v30-brotli-filter_3/0.16.1/play-v30-brotli-filter_3-0.16.1.jar:/Users/mat/Library/Caches/Coursier/v1/https/repo1.maven.org/maven2/org/scala-lang/scala-library/2.13.12/scala-library-2.13.12.jar:/Users/mat/Library/Caches/Coursier/v1/https/repo1.maven.org/maven2/org/scala-lang/scala3-library_3/3.4.2/scala3-library_3-3.4.2.jar -d /Users/mat/code/test/target/scala-3.4.2/classes
scala: ## Exception when compiling 1 sources to /Users/mat/code/test/target/scala-3.4.2/classes
dotty.tools.dotc.core.TypeError$$anon$1: object caps does not have a member type Cap
scala: Compilation failed when compiling to: /Users/mat/code/test/target/scala-3.4.2/classes
object caps does not have a member type Cap
Errors occurred while compiling module 'root'
Finished, saving caches…
Module 'root.root-build' was fully rebuilt due to project configuration/dependencies changes
Builder Scala sbt builder requested build stop
Executing post-compile tasks…
Synchronizing output directories…
05/07/2024, 12:01 - Build completed with 2 errors and 1 warning in 1 sec, 177 ms
That error seems to be related to multiple versions of scala-library being in the classpath, but there definitely isn't multiple versions in the classpath (as can be seen in the settings, it just has the 3.4.2 version and the 2.3.12 version which is completely normal for a Scala 3 compile).
It works fine if the library is removed from the classpath, the Scala version is dropped to a 3.3.x version or if the code has no use of implicits so it never enters the implicits phase of the compile.
The last filter I expected to be blocking my Ok("hi").withCookies(...)
operation was the Brotli filter, but it appears that it prevents Set-Cookie
headers appearing in responses.
I'm still investigating the exact reason for this
Under Play 2.9 the filter no longer works.
Requests using it end with this error:
ncaught error from thread [application-akka.actor.default-dispatcher-8]: 'void play.api.mvc.Result.<init>(play.api.mvc.ResponseHeader, play.api.http.HttpEntity, scala.Option, scala.Option, scala.collection.immutable.Seq)', shutting down JVM since 'akka.jvm-exit-on-fatal-error' is enabled for ActorSystem[application]
java.lang.NoSuchMethodError: 'void play.api.mvc.Result.<init>(play.api.mvc.ResponseHeader, play.api.http.HttpEntity, scala.Option, scala.Option, scala.collection.immutable.Seq)'
at play.filters.brotli.BrotliFilter.play$filters$brotli$BrotliFilter$$handleResult(BrotliFilter.scala:92)
at play.filters.brotli.BrotliFilter$$anon$1.$anonfun$apply$1(BrotliFilter.scala:77)
at scala.concurrent.impl.Promise$Transformation.run(Promise.scala:470)
at akka.dispatch.BatchingExecutor$AbstractBatch.processBatch(BatchingExecutor.scala:63)
at akka.dispatch.BatchingExecutor$BlockableBatch.$anonfun$run$1(BatchingExecutor.scala:100)
at scala.runtime.java8.JFunction0$mcV$sp.apply(JFunction0$mcV$sp.scala:18)
at scala.concurrent.BlockContext$.withBlockContext(BlockContext.scala:94)
at akka.dispatch.BatchingExecutor$BlockableBatch.run(BatchingExecutor.scala:100)
at akka.dispatch.TaskInvocation.run(AbstractDispatcher.scala:49)
at akka.dispatch.ForkJoinExecutorConfigurator$AkkaForkJoinTask.exec(ForkJoinExecutorConfigurator.scala:48)
at java.base/java.util.concurrent.ForkJoinTask.doExec(ForkJoinTask.java:373)
at java.base/java.util.concurrent.ForkJoinPool$WorkQueue.topLevelExec(ForkJoinPool.java:1182)
at java.base/java.util.concurrent.ForkJoinPool.scan(ForkJoinPool.java:1655)
at java.base/java.util.concurrent.ForkJoinPool.runWorker(ForkJoinPool.java:1622)
at java.base/java.util.concurrent.ForkJoinWorkerThread.run(ForkJoinWorkerThread.java:165)
I'm working to solve this, but thought I'd post here in the meantime in case it's familiar to you.
I have a play project that uses compile time DI (so not play's default dynamic runtime DI) - I mention that because I suspect it's probably related to this error:
play.api.UnexpectedException: Unexpected exception[UnsatisfiedLinkError: Failed to load Brotli native library]
at play.core.server.DevServerStart$$anon$1.reload(DevServerStart.scala:258)
at play.core.server.DevServerStart$$anon$1.get(DevServerStart.scala:148)
at play.core.server.netty.PlayRequestHandler.handle(PlayRequestHandler.scala:95)
at play.core.server.netty.PlayRequestHandler.channelRead(PlayRequestHandler.scala:203)
at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:379)
at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:365)
at io.netty.channel.AbstractChannelHandlerContext.fireChannelRead(AbstractChannelHandlerContext.java:357)
at com.typesafe.netty.http.HttpStreamsHandler.channelRead(HttpStreamsHandler.java:129)
at com.typesafe.netty.http.HttpStreamsServerHandler.channelRead(HttpStreamsServerHandler.java:96)
at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:379)
Caused by: java.lang.UnsatisfiedLinkError: Failed to load Brotli native library
at play.filters.brotli.loader.BrotliNativeLoader.ensureAvailability(BrotliNativeLoader.java:78)
at play.filters.brotli.Brotli.ensureAvailability(Brotli.java:69)
at play.filters.brotli.BrotliFilter.<init>(BrotliFilter.scala:42)
at play.filters.brotli.BrotliFilter.<init>(BrotliFilter.scala:50)
at ai.henricook.common.PlayFiltersModule.httpFilters(PlayFiltersModule.scala:29)
at ai.henricook.common.PlayFiltersModule.httpFilters$(PlayFiltersModule.scala:26)
at ai.henricook.ApplicationModule.httpFilters(ApplicationModule.scala:195)
at play.api.BuiltInComponents.httpRequestHandler(Application.scala:316)
at play.api.BuiltInComponents.httpRequestHandler$(Application.scala:309)
at play.api.BuiltInComponentsFromContext.httpRequestHandler$lzycompute(ApplicationLoader.scala:228)
Caused by: java.lang.NullPointerException: null
at java.base/java.util.Objects.requireNonNull(Objects.java:221)
at java.base/java.nio.file.Files.copy(Files.java:3035)
at play.filters.brotli.loader.BrotliNativeLoader.<clinit>(BrotliNativeLoader.java:47)
at play.filters.brotli.Brotli.<clinit>(Brotli.java:43)
at play.filters.brotli.BrotliFilter.<init>(BrotliFilter.scala:42)
at play.filters.brotli.BrotliFilter.<init>(BrotliFilter.scala:50)
at ai.henricook.common.PlayFiltersModule.httpFilters(PlayFiltersModule.scala:29)
at ai.henricook.common.PlayFiltersModule.httpFilters$(PlayFiltersModule.scala:26)
at ai.henricook.ApplicationModule.httpFilters(ApplicationModule.scala:195)
at play.api.BuiltInComponents.httpRequestHandler(Application.scala:316)
I'm instantiating the file like this:
new BrotliFilter(
shouldBrotli = (reqHeader, _) => {
reqHeader.contentType.exists(cType =>
List(
"application/json",
"text/plain",
).contains(cType)
)
}
)
and adding it to the list of filters we use for all our other filters (including play default filters) in our class that extends Play's HttpFiltersComponents
A declarative, efficient, and flexible JavaScript library for building user interfaces.
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google ❤️ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.