@@ -4,6 +4,7 @@ import io.github.oshai.kotlinlogging.KotlinLogging
44import io.ktor.client.*
55import io.ktor.client.plugins.*
66import io.ktor.client.request.*
7+ import io.ktor.client.statement.HttpResponse
78import io.ktor.http.*
89import kotlinx.serialization.json.Json
910import kotlinx.serialization.json.jsonArray
@@ -27,22 +28,43 @@ class WillhabenAPIImpl(private val httpClient: HttpClient) : WillhabenAPI, KoinC
2728 val logger = KotlinLogging .logger {}
2829
2930 override suspend fun fetchListing (url : String ): WillhabenListing ? {
30- val mappedUrl = parseWillhabenUrl(url)
31- if (mappedUrl.segments.firstOrNull() != " iad" || ! mappedUrl.segments.contains(" d" )) throw IllegalArgumentException (" Not a listing URL: $url " )
31+ var mappedUrl = parseWillhabenUrl(url)
32+ if (
33+ mappedUrl.segments.firstOrNull() != " iad"
34+ || (
35+ ! mappedUrl.segments.contains(" d" )
36+ && mappedUrl.segments.last() != " object"
37+ )
38+ ) throw IllegalArgumentException (" Not a listing URL: $url " )
3239
33- val response = try {
34- noRedirectClient.get(mappedUrl)
35- } catch (redirect: RedirectResponseException ) {
36- val location = redirect.response.headers[HttpHeaders .Location ] ? : throw redirect
40+ lateinit var response: HttpResponse
3741
38- if (location.contains(" ?fromExpiredAdId=" )) {
39- logger.warn { " Listing $url is expired" }
40- return null
41- }
42- if (! location.contains(" /d/" )) throw IllegalArgumentException (" Invalid redirect location: $location " )
42+ for (attempt in 0 .. 3 ) {
43+ try {
44+ logger.debug { " Attempting to fetch $mappedUrl - attempt $attempt " }
45+ response = noRedirectClient.get(mappedUrl)
46+ break
47+ } catch (redirect: RedirectResponseException ) {
48+ val location = redirect.response.headers[HttpHeaders .Location ] ? : throw redirect
49+
50+ if (location.contains(" ?fromExpiredAdId=" )) {
51+ logger.warn { " Listing $url is expired" }
52+ return null
53+ }
54+ if (! location.contains(" /d/" )) throw IllegalArgumentException (" Invalid redirect location: $location " )
4355
44- // redirect may be valid (http -> https?) - try the new URL
45- noRedirectClient.get(location)
56+ // redirect may be valid (/iad/object?adId=... -> /iad/.../d/...) - try the new URL
57+ val newUrlBuilder = URLBuilder ()
58+ newUrlBuilder.protocol = URLProtocol .HTTPS
59+ // since we manually follow the redirect, use WILLHABEN_HOST as the default
60+ newUrlBuilder.host = WILLHABEN_HOST
61+ // and override the path with the relative path gotten from the original request
62+ newUrlBuilder.path(location)
63+ val newUrl = newUrlBuilder.build()
64+
65+ logger.debug { " Redirected to $newUrl " }
66+ mappedUrl = newUrl
67+ }
4668 }
4769
4870 val props = response.parsePageProps(json)
0 commit comments