1
0
mirror of https://gitlab.com/mangadex-pub/mangadex_at_home.git synced 2024-11-16 16:12:32 +01:00

Merge branch 'fix-tls-and-crashes' into 'master'

Fix tls and crashes

See merge request mangadex-pub/mangadex_at_home!99
This commit is contained in:
carbotaniuman 2022-02-17 06:27:44 +00:00
commit 85dce402df
6 changed files with 70 additions and 43 deletions

View File

@ -17,6 +17,13 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
### Security ### Security
## [2.0.2] - 2022-02-16
### Removed
- [2022-02-16] Remove TLS 1.0 and 1.1 support [@carbotaniuman].
### Fixed
- [2022-02-16] Fix uncatched exceptions killing threads and not being logged [@carbotaniuman].
## [2.0.1] - 2021-05-27 ## [2.0.1] - 2021-05-27
### Added ### Added
- [2021-05-27] Added SNI check to prevent people from simply scanning nodes [@carbotaniuman]. - [2021-05-27] Added SNI check to prevent people from simply scanning nodes [@carbotaniuman].
@ -396,7 +403,8 @@ This release contains many breaking changes! Of note are the changes to the cach
### Fixed ### Fixed
- [2020-06-11] Tweaked logging configuration to reduce log file sizes by [@carbotaniuman]. - [2020-06-11] Tweaked logging configuration to reduce log file sizes by [@carbotaniuman].
[Unreleased]: https://gitlab.com/mangadex/mangadex_at_home/-/compare/2.0.0...HEAD [Unreleased]: https://gitlab.com/mangadex/mangadex_at_home/-/compare/2.0.2...HEAD
[2.0.2]: https://gitlab.com/mangadex/mangadex_at_home/-/compare/2.0.1...2.0.2
[2.0.1]: https://gitlab.com/mangadex/mangadex_at_home/-/compare/2.0.0...2.0.1 [2.0.1]: https://gitlab.com/mangadex/mangadex_at_home/-/compare/2.0.0...2.0.1
[2.0.0]: https://gitlab.com/mangadex/mangadex_at_home/-/compare/2.0.0-rc14...2.0.0 [2.0.0]: https://gitlab.com/mangadex/mangadex_at_home/-/compare/2.0.0-rc14...2.0.0
[2.0.0-rc14]: https://gitlab.com/mangadex/mangadex_at_home/-/compare/2.0.0-rc13...2.0.0-rc14 [2.0.0-rc14]: https://gitlab.com/mangadex/mangadex_at_home/-/compare/2.0.0-rc13...2.0.0-rc14

View File

@ -24,7 +24,6 @@ import io.micrometer.prometheus.PrometheusConfig
import io.micrometer.prometheus.PrometheusMeterRegistry import io.micrometer.prometheus.PrometheusMeterRegistry
import mdnet.cache.ImageStorage import mdnet.cache.ImageStorage
import mdnet.data.Statistics import mdnet.data.Statistics
import mdnet.logging.error
import mdnet.logging.info import mdnet.logging.info
import mdnet.logging.warn import mdnet.logging.warn
import mdnet.metrics.DefaultMicrometerMetrics import mdnet.metrics.DefaultMicrometerMetrics
@ -188,7 +187,7 @@ class ServerManager(
} }
} }
} catch (e: Exception) { } catch (e: Exception) {
LOGGER.error(e) { "Main loop failed" } LOGGER.warn(e) { "Main loop failed" }
} }
}, },
5, 5, TimeUnit.SECONDS 5, 5, TimeUnit.SECONDS

View File

@ -25,6 +25,7 @@ import com.fasterxml.jackson.module.kotlin.jacksonObjectMapper
import com.fasterxml.jackson.module.kotlin.readValue import com.fasterxml.jackson.module.kotlin.readValue
import mdnet.logging.info import mdnet.logging.info
import mdnet.logging.trace import mdnet.logging.trace
import mdnet.logging.warn
import org.apache.commons.io.file.PathUtils import org.apache.commons.io.file.PathUtils
import org.ktorm.database.Database import org.ktorm.database.Database
import org.ktorm.dsl.* import org.ktorm.dsl.*
@ -58,7 +59,7 @@ class ImageStorage(
private val cacheDirectory: Path, private val cacheDirectory: Path,
private val database: Database, private val database: Database,
autoPrune: Boolean = true autoPrune: Boolean = true
) { ) : AutoCloseable {
private val tempCacheDirectory = cacheDirectory.resolve("tmp") private val tempCacheDirectory = cacheDirectory.resolve("tmp")
private val evictor: ScheduledExecutorService = Executors.newScheduledThreadPool(2) private val evictor: ScheduledExecutorService = Executors.newScheduledThreadPool(2)
@ -89,6 +90,7 @@ class ImageStorage(
evictor.scheduleWithFixedDelay( evictor.scheduleWithFixedDelay(
{ {
try {
val toUpdate = HashSet<String>() val toUpdate = HashSet<String>()
queue.drainTo(toUpdate) queue.drainTo(toUpdate)
val now = Instant.now() val now = Instant.now()
@ -107,18 +109,24 @@ class ImageStorage(
} }
} }
calculateSize() calculateSize()
} catch (e: Exception) {
LOGGER.warn(e) { "Error updating LRU $this" }
}
}, },
1, 1, TimeUnit.MINUTES 30, 30, TimeUnit.SECONDS
) )
// evict LRU cache every 3 minutes
if (autoPrune) { if (autoPrune) {
evictor.scheduleWithFixedDelay( evictor.scheduleWithFixedDelay(
{ {
try {
calculateSize() calculateSize()
pruneImages() pruneImages()
} catch (e: Exception) {
LOGGER.warn(e) { "Error pruning images" }
}
}, },
0, 3, TimeUnit.MINUTES 0, 1, TimeUnit.MINUTES
) )
} }
} }
@ -255,7 +263,7 @@ class ImageStorage(
} }
} }
fun close() { override fun close() {
evictor.shutdown() evictor.shutdown()
evictor.awaitTermination(10, TimeUnit.SECONDS) evictor.awaitTermination(10, TimeUnit.SECONDS)
} }

View File

@ -175,7 +175,7 @@ class Netty(
val certs = getX509Certs(tls.certificate) val certs = getX509Certs(tls.certificate)
val sslContext = SslContextBuilder val sslContext = SslContextBuilder
.forServer(getPrivateKey(tls.privateKey), certs) .forServer(getPrivateKey(tls.privateKey), certs)
.protocols("TLSv1.3", "TLSv1.2", "TLSv1.1", "TLSv1") .protocols("TLSv1.3", "TLSv1.2")
.build() .build()
val bootstrap = ServerBootstrap() val bootstrap = ServerBootstrap()

View File

@ -39,12 +39,14 @@ class ImageStorageTest : FreeSpec() {
override fun isolationMode() = IsolationMode.InstancePerTest override fun isolationMode() = IsolationMode.InstancePerTest
init { init {
val imageStorage = ImageStorage( val imageStorage = autoClose(
ImageStorage(
maxSize = 5, maxSize = 5,
cacheDirectory = tempdir().toPath(), cacheDirectory = tempdir().toPath(),
database = Database.connect("jdbc:sqlite:${tempfile()}"), database = Database.connect("jdbc:sqlite:${tempfile()}"),
autoPrune = false, autoPrune = false,
) )
)
val testMeta = ImageMetadata("a", "a", 123) val testMeta = ImageMetadata("a", "a", 123)
@ -81,7 +83,8 @@ class ImageStorageTest : FreeSpec() {
writer.stream.write(ByteArray(12)) writer.stream.write(ByteArray(12))
writer.abort() writer.abort()
"should not update size" { "should not update size even if calculated" {
imageStorage.calculateSize()
imageStorage.size.shouldBeZero() imageStorage.size.shouldBeZero()
} }
} }
@ -157,14 +160,17 @@ class ImageStorageSlowTest : FreeSpec() {
override fun isolationMode() = IsolationMode.InstancePerTest override fun isolationMode() = IsolationMode.InstancePerTest
init { init {
val imageStorage = ImageStorage( val imageStorage = autoClose(
ImageStorage(
maxSize = 4097, maxSize = 4097,
cacheDirectory = tempdir().toPath(), cacheDirectory = tempdir().toPath(),
database = Database.connect("jdbc:sqlite:${tempfile()}"), database = Database.connect("jdbc:sqlite:${tempfile()}"),
) )
)
"autoPrune" - { "autoPrune" - {
"should update size eventually" { "should update size eventually" {
println("1 - $imageStorage")
val writer = imageStorage.storeImage("test", ImageMetadata("a", "a", 4096)) val writer = imageStorage.storeImage("test", ImageMetadata("a", "a", 4096))
writer.shouldNotBeNull() writer.shouldNotBeNull()
@ -177,6 +183,7 @@ class ImageStorageSlowTest : FreeSpec() {
} }
"should prune if insufficient size eventually" { "should prune if insufficient size eventually" {
println("2 - $imageStorage")
imageStorage.maxSize = 10000 imageStorage.maxSize = 10000
val writer = imageStorage.storeImage("test", ImageMetadata("a", "a", 123)) val writer = imageStorage.storeImage("test", ImageMetadata("a", "a", 123))
@ -185,6 +192,7 @@ class ImageStorageSlowTest : FreeSpec() {
writer.stream.write(ByteArray(8192)) writer.stream.write(ByteArray(8192))
writer.commit(8192).shouldBeTrue() writer.commit(8192).shouldBeTrue()
imageStorage.calculateSize()
eventually(Duration.minutes(5)) { eventually(Duration.minutes(5)) {
imageStorage.size.shouldBeZero() imageStorage.size.shouldBeZero()
} }

View File

@ -116,12 +116,14 @@ class ImageServerTest : FreeSpec() {
} }
"with real cache" - { "with real cache" - {
val storage = ImageStorage( val storage = autoClose(
ImageStorage(
maxSize = 100000, maxSize = 100000,
cacheDirectory = tempdir().toPath(), cacheDirectory = tempdir().toPath(),
database = Database.connect("jdbc:sqlite:${tempfile()}"), database = Database.connect("jdbc:sqlite:${tempfile()}"),
autoPrune = false, autoPrune = false,
) )
)
val server = ImageServer( val server = ImageServer(
storage, storage,
@ -161,12 +163,14 @@ class ImageServerTest : FreeSpec() {
"failed upstream responses" - { "failed upstream responses" - {
val client = mockk<HttpHandler>() val client = mockk<HttpHandler>()
val storage = ImageStorage( val storage = autoClose(
ImageStorage(
maxSize = 100000, maxSize = 100000,
cacheDirectory = tempdir().toPath(), cacheDirectory = tempdir().toPath(),
database = Database.connect("jdbc:sqlite:${tempfile()}"), database = Database.connect("jdbc:sqlite:${tempfile()}"),
autoPrune = false, autoPrune = false,
) )
)
val server = ImageServer( val server = ImageServer(
storage, storage,