Skip to content

Commit 1b712d4

Browse files
committed
GH-20: Fix Link pagination Link header parsing
Fixes: #20 The link in the `timeline` response header may come with `rel="prev"`. Since we are interested in the `rel="next"`, remove everything before `rel="prev"` including this `prev` token
1 parent 0e8f72d commit 1b712d4

File tree

2 files changed

+39
-7
lines changed

2 files changed

+39
-7
lines changed

src/main/kotlin/io/spring/github/api/WebClientGitHubApi.kt

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2002-2019 the original author or authors.
2+
* Copyright 2002-2025 the original author or authors.
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
@@ -35,6 +35,7 @@ import java.util.*
3535

3636
/**
3737
* @author Rob Winch
38+
* @author Artem Bilan
3839
*/
3940
class WebClientGitHubApi(val webClient: WebClient = WebClient.create(), val baseGitHubUrl: String = "https://api.github.com") : GitHubApi {
4041
override fun getPermissionForDefaultLogin(repositoryRef: RepositoryRef, accessToken: String): Mono<Permission> {
@@ -289,10 +290,17 @@ class WebClientGitHubApi(val webClient: WebClient = WebClient.create(), val base
289290
}
290291

291292
private fun next(httpHeaders : HttpHeaders) : String? {
292-
val linkHeaderValue = httpHeaders.getFirst("Link")
293+
var linkHeaderValue = httpHeaders.getFirst("Link")
293294
if (linkHeaderValue == null) {
294295
return null
295296
}
297+
298+
val relPrevToken = """rel="prev", """
299+
val index = linkHeaderValue.indexOf(relPrevToken)
300+
if (index != -1) {
301+
linkHeaderValue = linkHeaderValue.substring(index + relPrevToken.length)
302+
}
303+
296304
val nextRegex = """.*?<(.*?)>; rel="next".*""".toRegex()
297305
if (!linkHeaderValue.matches(nextRegex)) {
298306
return null

src/test/kotlin/io/spring/github/RegexTest.kt

Lines changed: 29 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -17,15 +17,39 @@
1717
package io.spring.github
1818

1919
import org.assertj.core.api.Assertions.assertThat
20+
import org.assertj.core.api.Assertions.assertThatNoException
2021
import org.junit.jupiter.api.Test
22+
import java.net.URI
2123

2224
/**
2325
* @author Rob Winch
2426
*/
2527
class RegexTest {
26-
@Test
27-
fun regex() {
28-
val r = """Fixes: gh-\d+""".toRegex()
29-
assertThat(r.containsMatchIn("Hi\n\nHello\r\n\r\nFixes: gh-123")).isTrue()
30-
}
28+
29+
@Test
30+
fun regex() {
31+
val r = """Fixes: gh-\d+""".toRegex()
32+
assertThat(r.containsMatchIn("Hi\n\nHello\r\n\r\nFixes: gh-123")).isTrue()
33+
}
34+
35+
@Test
36+
fun nextLinkReplace() {
37+
var linkHeaderValue =
38+
"""<https://api.github.com/repositories/2090979/issues/10083/timeline?page=1>; rel="prev", <https://api.github.com/repositories/2090979/issues/10083/timeline?page=3>; rel="next", <https://api.github.com/repositories/2090979/issues/10083/timeline?page=3>; rel="last", <https://api.github.com/repositories/2090979/issues/10083/timeline?page=1>; rel="first""""
39+
40+
val relPrevToken = """rel="prev", """
41+
42+
val index = linkHeaderValue.indexOf(relPrevToken)
43+
if (index != -1) {
44+
linkHeaderValue = linkHeaderValue.substring(index + relPrevToken.length)
45+
}
46+
47+
val nextRegex = """.*?<(.*?)>; rel="next".*"""
48+
assertThat(linkHeaderValue).matches(nextRegex)
49+
50+
assertThatNoException().isThrownBy {
51+
URI.create(linkHeaderValue.replace(nextRegex.toRegex(), "$1"))
52+
}
53+
}
54+
3155
}

0 commit comments

Comments
 (0)