Merge branch 'fix-4xx-caching' into expermential_buffer_size_knob

This commit is contained in:
AviKav 2020-07-14 04:05:02 -04:00
commit dcd05dc6a1
2 changed files with 106 additions and 85 deletions

View file

@ -1,79 +1,79 @@
plugins { plugins {
id "java" id "java"
id "org.jetbrains.kotlin.jvm" version "1.3.72" id "org.jetbrains.kotlin.jvm" version "1.3.72"
id "application" id "application"
id "com.github.johnrengelman.shadow" version "5.2.0" id "com.github.johnrengelman.shadow" version "5.2.0"
id "com.diffplug.gradle.spotless" version "4.4.0" id "com.diffplug.gradle.spotless" version "4.4.0"
id "dev.afanasev.sekret" version "0.0.3" id "dev.afanasev.sekret" version "0.0.3"
} }
group = "com.mangadex" group = "com.mangadex"
version = "git describe --tags --dirty".execute().text.trim() version = "git describe --tags --dirty".execute().text.trim()
mainClassName = "mdnet.base.Main" mainClassName = "mdnet.base.Main"
repositories { repositories {
mavenCentral() mavenCentral()
jcenter() jcenter()
} }
configurations { configurations {
runtime.exclude group: "org.jetbrains.kotlinx", module: "kotlinx-coroutines-core" runtime.exclude group: "org.jetbrains.kotlinx", module: "kotlinx-coroutines-core"
runtime.exclude group: "com.sun.mail", module: "javax.mail" runtime.exclude group: "com.sun.mail", module: "javax.mail"
} }
dependencies { dependencies {
compileOnly group: "dev.afanasev", name: "sekret-annotation", version: "0.0.3" compileOnly group: "dev.afanasev", name: "sekret-annotation", version: "0.0.3"
implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk8" implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk8"
implementation "org.jetbrains.kotlin:kotlin-reflect" implementation "org.jetbrains.kotlin:kotlin-reflect"
implementation group: "commons-io", name: "commons-io", version: "2.7" implementation group: "commons-io", name: "commons-io", version: "2.7"
implementation group: "org.http4k", name: "http4k-core", version: "$http_4k_version" implementation group: "org.http4k", name: "http4k-core", version: "$http_4k_version"
implementation group: "org.http4k", name: "http4k-format-jackson", version: "$http_4k_version" implementation group: "org.http4k", name: "http4k-format-jackson", version: "$http_4k_version"
implementation group: "com.fasterxml.jackson.datatype", name: "jackson-datatype-jsr310", version: "2.11.1" implementation group: "com.fasterxml.jackson.datatype", name: "jackson-datatype-jsr310", version: "2.11.1"
implementation group: "org.http4k", name: "http4k-client-apache", version: "$http_4k_version" implementation group: "org.http4k", name: "http4k-client-apache", version: "$http_4k_version"
implementation group: "org.http4k", name: "http4k-server-netty", version: "$http_4k_version" implementation group: "org.http4k", name: "http4k-server-netty", version: "$http_4k_version"
runtimeOnly group: "io.netty", name: "netty-tcnative-boringssl-static", version: "2.0.30.Final" runtimeOnly group: "io.netty", name: "netty-tcnative-boringssl-static", version: "2.0.30.Final"
implementation group: "ch.qos.logback", name: "logback-classic", version: "1.3.0-alpha4" implementation group: "ch.qos.logback", name: "logback-classic", version: "1.3.0-alpha4"
implementation group: "org.jetbrains.exposed", name: "exposed-core", version: "$exposed_version" implementation group: "org.jetbrains.exposed", name: "exposed-core", version: "$exposed_version"
implementation group: "org.jetbrains.exposed", name: "exposed-dao", version: "$exposed_version" implementation group: "org.jetbrains.exposed", name: "exposed-dao", version: "$exposed_version"
implementation group: "org.jetbrains.exposed", name: "exposed-jdbc", version: "$exposed_version" implementation group: "org.jetbrains.exposed", name: "exposed-jdbc", version: "$exposed_version"
implementation group: "org.xerial", name: "sqlite-jdbc", version: "3.30.1" implementation group: "org.xerial", name: "sqlite-jdbc", version: "3.30.1"
implementation "com.goterl.lazycode:lazysodium-java:4.2.6" implementation "com.goterl.lazycode:lazysodium-java:4.3.0"
implementation "net.java.dev.jna:jna:5.5.0" implementation "net.java.dev.jna:jna:5.5.0"
} }
java { java {
sourceCompatibility = JavaVersion.VERSION_1_8 sourceCompatibility = JavaVersion.VERSION_1_8
targetCompatibility = JavaVersion.VERSION_1_8 targetCompatibility = JavaVersion.VERSION_1_8
} }
spotless { spotless {
lineEndings 'UNIX' lineEndings 'UNIX'
java { java {
targetExclude("build/generated/**/*") targetExclude("build/generated/**/*")
eclipse() eclipse()
removeUnusedImports() removeUnusedImports()
trimTrailingWhitespace() trimTrailingWhitespace()
endWithNewline() endWithNewline()
} }
kotlin { kotlin {
ktlint() ktlint()
trimTrailingWhitespace() trimTrailingWhitespace()
endWithNewline() endWithNewline()
} }
} }
tasks.register("generateVersion", Copy) { tasks.register("generateVersion", Copy) {
def templateContext = [version: version] def templateContext = [version: version]
inputs.properties templateContext inputs.properties templateContext
from "src/template/java" from "src/template/java"
into "$buildDir/generated/java" into "$buildDir/generated/java"
expand templateContext expand templateContext
} }
sourceSets.main.java.srcDir generateVersion.outputs.files sourceSets.main.java.srcDir generateVersion.outputs.files

View file

@ -138,13 +138,25 @@ class ImageServer(
} }
val imageId = printHexString(rc4Bytes) val imageId = printHexString(rc4Bytes)
val snapshot = cache.getUnsafe(imageId.toCacheId()) // These shouldn't be var but I don't want to touch the original conditional logic
val imageDatum = synchronized(database) { var snapshot = cache.getUnsafe(imageId.toCacheId())
var imageDatum = synchronized(database) {
transaction(database) { transaction(database) {
ImageDatum.findById(imageId) ImageDatum.findById(imageId)
} }
} }
// TODO: Cleanup messy conditionals
// Ensure that cached file isn't a non-image from the Great Cache Propagation
val flaresFault = imageDatum != null && imageDatum.contentType.isImageMimetype().not()
if (flaresFault) {
snapshot?.close(); snapshot = null
cache.removeUnsafe(imageId.toCacheId()); imageDatum = null
LOGGER.warn { "Removing cache file for $sanitizedUri left over the Great Cache Propagation" }
}
if (snapshot != null && imageDatum != null) { if (snapshot != null && imageDatum != null) {
request.handleCacheHit(sanitizedUri, getRc4(rc4Bytes), snapshot, imageDatum) request.handleCacheHit(sanitizedUri, getRc4(rc4Bytes), snapshot, imageDatum)
} else { } else {
@ -174,6 +186,8 @@ class ImageServer(
} }
} }
private fun String.isImageMimetype() = this.toLowerCase().startsWith("image/")
private fun Request.handleCacheHit(sanitizedUri: String, cipher: Cipher, snapshot: DiskLruCache.Snapshot, imageDatum: ImageDatum): Response { private fun Request.handleCacheHit(sanitizedUri: String, cipher: Cipher, snapshot: DiskLruCache.Snapshot, imageDatum: ImageDatum): Response {
// our files never change, so it's safe to use the browser cache // our files never change, so it's safe to use the browser cache
return if (this.header("If-Modified-Since") != null) { return if (this.header("If-Modified-Since") != null) {
@ -217,19 +231,26 @@ class ImageServer(
val mdResponse = client(Request(Method.GET, "${serverSettings.imageServer}$sanitizedUri")) val mdResponse = client(Request(Method.GET, "${serverSettings.imageServer}$sanitizedUri"))
val contentType = mdResponse.header("Content-Type")
val contentLength = mdResponse.header("Content-Length")
val lastModified = mdResponse.header("Last-Modified")
if (mdResponse.status != Status.OK) { if (mdResponse.status != Status.OK) {
LOGGER.trace { "Upstream query for $sanitizedUri errored with status ${mdResponse.status}" } LOGGER.trace { "Upstream query for $sanitizedUri errored with status ${mdResponse.status}" }
mdResponse.close()
return Response(mdResponse.status)
}
contentType!!
if (!contentType.isImageMimetype()) {
LOGGER.trace { "Upstream query for $sanitizedUri returned bad mimetype $contentType" }
mdResponse.close() mdResponse.close()
return Response(mdResponse.status) return Response(mdResponse.status)
} }
LOGGER.trace { "Upstream query for $sanitizedUri succeeded" } LOGGER.trace { "Upstream query for $sanitizedUri succeeded" }
val contentType = mdResponse.header("Content-Type")!!
val contentLength = mdResponse.header("Content-Length")
val lastModified = mdResponse.header("Last-Modified")
val editor = cache.editUnsafe(imageId.toCacheId()) val editor = cache.editUnsafe(imageId.toCacheId())
// A null editor means that this file is being written to // A null editor means that this file is being written to