-
Notifications
You must be signed in to change notification settings - Fork 422
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Optimize parsing headers for pekko-http and akka-http (#3575)
- Loading branch information
1 parent
e76a854
commit 937a96c
Showing
6 changed files
with
62 additions
and
4 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
29 changes: 29 additions & 0 deletions
29
server/akka-http-server/src/main/scala/sttp/tapir/server/akkahttp/ContentTypeCache.scala
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,29 @@ | ||
package sttp.tapir.server.akkahttp | ||
|
||
import akka.http.scaladsl.model.ContentType | ||
import scala.collection.concurrent.TrieMap | ||
|
||
/** Pekko-specific ConentType has to be created if an endpoint overrides it, but we want to reduce overhead of the expensive | ||
* ContentType.parse operation if possible. Parsing may also happen for cases not listed explictly in | ||
* PekkoToResponseBody.formatToContentType. This cache doesn't have to save atomically, because the worst case scenario is that we parse he | ||
* same header a few times before it's saved. The cache is not cleared, because the number of different content types is limited and the | ||
* cache is not expected to grow too much. The only exception is when there is a boundary in the header, but in such situation the endpoint | ||
* contentType shouldn't be overriden. Just in case this happens, we limit the cache size. | ||
*/ | ||
private[akkahttp] object ContentTypeCache { | ||
private val cache = TrieMap[String, ContentType]() | ||
private val Limit = 100 | ||
|
||
def getOrParse(headerValue: String): ContentType = { | ||
cache.get(headerValue) match { | ||
case Some(contentType) => | ||
contentType | ||
case None => | ||
val contentType = | ||
ContentType.parse(headerValue).getOrElse(throw new IllegalArgumentException(s"Cannot parse content type: $headerValue")) | ||
// We don't want to fill the cache with parameterized media types (BTW charset does not appear in params) | ||
val _ = if (cache.size <= Limit && contentType.mediaType.params.isEmpty) cache.putIfAbsent(headerValue, contentType) | ||
contentType | ||
} | ||
} | ||
} |
29 changes: 29 additions & 0 deletions
29
server/pekko-http-server/src/main/scala/sttp/tapir/server/pekkohttp/ContentTypeCache.scala
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,29 @@ | ||
package sttp.tapir.server.pekkohttp | ||
|
||
import org.apache.pekko.http.scaladsl.model.ContentType | ||
import scala.collection.concurrent.TrieMap | ||
|
||
/** Pekko-specific ConentType has to be created if an endpoint overrides it, but we want to reduce overhead of the expensive | ||
* ContentType.parse operation if possible. Parsing may also happen for cases not listed explictly in | ||
* PekkoToResponseBody.formatToContentType. This cache doesn't have to save atomically, because the worst case scenario is that we parse he | ||
* same header a few times before it's saved. The cache is not cleared, because the number of different content types is limited and the | ||
* cache is not expected to grow too much. The only exception is when there is a boundary in the header, but in such situation the endpoint | ||
* contentType shouldn't be overriden. Just in case this happens, we limit the cache size. | ||
*/ | ||
private[pekkohttp] object ContentTypeCache { | ||
private val cache = TrieMap[String, ContentType]() | ||
private val Limit = 100 | ||
|
||
def getOrParse(headerValue: String): ContentType = { | ||
cache.get(headerValue) match { | ||
case Some(contentType) => | ||
contentType | ||
case None => | ||
val contentType = | ||
ContentType.parse(headerValue).getOrElse(throw new IllegalArgumentException(s"Cannot parse content type: $headerValue")) | ||
// We don't want to fill the cache with parameterized media types (BTW charset does not appear in params) | ||
val _ = if (cache.size <= Limit && contentType.mediaType.params.isEmpty) cache.putIfAbsent(headerValue, contentType) | ||
contentType | ||
} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters