Skip to content

Commit 62f8fb8

Browse files
authored
Normalize URLs (readium#534)
1 parent c4eab48 commit 62f8fb8

File tree

28 files changed

+177
-27
lines changed

28 files changed

+177
-27
lines changed

readium/lcp/src/main/java/org/readium/r2/lcp/LcpDecryptor.kt

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@ import org.readium.r2.shared.util.Try
2222
import org.readium.r2.shared.util.Url
2323
import org.readium.r2.shared.util.data.ReadError
2424
import org.readium.r2.shared.util.flatMap
25+
import org.readium.r2.shared.util.getEquivalent
2526
import org.readium.r2.shared.util.getOrElse
2627
import org.readium.r2.shared.util.resource.FailureResource
2728
import org.readium.r2.shared.util.resource.Resource
@@ -38,7 +39,7 @@ internal class LcpDecryptor(
3839

3940
fun transform(url: Url, resource: Resource): Resource {
4041
return resource.flatMap {
41-
val encryption = encryptionData[url]
42+
val encryption = encryptionData.getEquivalent(url)
4243

4344
// Checks if the resource is encrypted and whether the encryption schemes of the resource
4445
// and the DRM license are the same.

readium/lcp/src/main/java/org/readium/r2/lcp/license/License.kt

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@ import org.readium.r2.lcp.service.DeviceService
3131
import org.readium.r2.lcp.service.LcpClient
3232
import org.readium.r2.lcp.service.LicensesRepository
3333
import org.readium.r2.lcp.service.NetworkService
34+
import org.readium.r2.shared.DelicateReadiumApi
3435
import org.readium.r2.shared.InternalReadiumApi
3536
import org.readium.r2.shared.extensions.tryOrNull
3637
import org.readium.r2.shared.util.Instant
@@ -246,6 +247,7 @@ internal class License private constructor(
246247
override val canReturnPublication: Boolean
247248
get() = status?.link(StatusDocument.Rel.Return) != null
248249

250+
@OptIn(DelicateReadiumApi::class)
249251
override suspend fun returnPublication(): Try<Unit, LcpError> {
250252
try {
251253
val status = this.documents.status

readium/navigator/src/main/java/org/readium/r2/navigator/R2BasicWebView.kt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -587,7 +587,7 @@ internal open class R2BasicWebView(context: Context, attrs: AttributeSet) : WebV
587587
val requestUrl = request.url.toUrl() ?: return false
588588

589589
// FIXME: I doubt this can work well. hasGesture considers itself unreliable.
590-
return if (urlNotToOverrideLoading == requestUrl && request.hasGesture()) {
590+
return if (urlNotToOverrideLoading?.isEquivalent(requestUrl) == true && request.hasGesture()) {
591591
urlNotToOverrideLoading = null
592592
false
593593
} else {

readium/navigator/src/main/java/org/readium/r2/navigator/epub/EpubNavigatorFragment.kt

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -621,7 +621,7 @@ public class EpubNavigatorFragment internal constructor(
621621
val page = resources.withIndex().firstOrNull { (_, res) ->
622622
when (res) {
623623
is PageResource.EpubReflowable ->
624-
res.link.url() == href
624+
res.link.url().isEquivalent(href)
625625
is PageResource.EpubFxl ->
626626
res.leftUrl?.toString()?.endsWith(href.toString()) == true || res.rightUrl?.toString()?.endsWith(
627627
href.toString()
@@ -785,7 +785,10 @@ public class EpubNavigatorFragment internal constructor(
785785
paginationListener?.onPageLoaded()
786786

787787
val href = link.url()
788-
if (state is State.Initializing || (state as? State.Loading)?.initialResourceHref == href) {
788+
if (state is State.Initializing || (state as? State.Loading)?.initialResourceHref?.isEquivalent(
789+
href
790+
) == true
791+
) {
789792
state = State.Ready
790793
}
791794

readium/navigator/src/main/java/org/readium/r2/navigator/extensions/Publication.kt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,7 @@ public fun Publication.normalizeLocator(locator: Locator): Locator {
4040
?: return locator
4141
)
4242
} else { // Remote publication
43-
// Check that the locator HREF relative to `self` exists int he manifest.
43+
// Check that the locator HREF relative to `self` exists in the manifest.
4444
val relativeHref = self.relativize(locator.href)
4545
if (linkWithHref(relativeHref) != null) {
4646
locator.copy(href = relativeHref)

readium/navigator/src/main/java/org/readium/r2/navigator/media/MediaService.kt

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@ import kotlinx.coroutines.flow.*
2929
import org.readium.r2.navigator.extensions.let
3030
import org.readium.r2.navigator.extensions.splitAt
3131
import org.readium.r2.navigator.media.extensions.publicationId
32+
import org.readium.r2.shared.DelicateReadiumApi
3233
import org.readium.r2.shared.InternalReadiumApi
3334
import org.readium.r2.shared.publication.Link
3435
import org.readium.r2.shared.publication.Locator
@@ -141,6 +142,7 @@ public open class MediaService : MediaBrowserServiceCompat(), CoroutineScope by
141142
private var notificationId: Int? = null
142143
private var notification: Notification? = null
143144

145+
@OptIn(DelicateReadiumApi::class)
144146
private val mediaPlayerListener = object : MediaPlayer.Listener {
145147

146148
/**
@@ -168,7 +170,7 @@ public open class MediaService : MediaBrowserServiceCompat(), CoroutineScope by
168170
?.let { navigator.publication.linkWithHref(it) }
169171
?.let { navigator.publication.locatorFromLink(it) }
170172

171-
if (locator != null && href != null && locator.href != href) {
173+
if (locator != null && href != null && locator.href.isEquivalent(href)) {
172174
Timber.e(
173175
"Ambiguous playback location provided. HREF `$href` doesn't match locator $locator."
174176
)

readium/opds/src/main/java/org/readium/r2/opds/OPDS1Parser.kt

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212
package org.readium.r2.opds
1313

1414
import java.net.URL
15+
import org.readium.r2.shared.DelicateReadiumApi
1516
import org.readium.r2.shared.InternalReadiumApi
1617
import org.readium.r2.shared.extensions.toList
1718
import org.readium.r2.shared.extensions.toMap
@@ -101,6 +102,7 @@ public class OPDS1Parser {
101102
public fun parse(xmlData: ByteArray, url: URL): ParseData =
102103
throw NotImplementedError()
103104

105+
@OptIn(DelicateReadiumApi::class)
104106
private fun parseFeed(root: ElementNode, url: Url): Feed {
105107
val feedTitle = root.getFirst("title", Namespaces.Atom)?.text
106108
?: throw Exception(OPDSParserError.MissingTitle.name)
@@ -273,6 +275,7 @@ public class OPDS1Parser {
273275
}.mapFailure { ErrorException(it) }
274276
}
275277

278+
@OptIn(DelicateReadiumApi::class)
276279
private fun parseEntry(entry: ElementNode, baseUrl: Url): Publication? {
277280
// A title is mandatory
278281
val title = entry.getFirst("title", Namespaces.Atom)?.text

readium/shared/src/main/java/org/readium/r2/shared/MediaOverlays.kt

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ package org.readium.r2.shared
1111

1212
import java.io.Serializable
1313
import org.readium.r2.shared.util.Url
14+
import org.readium.r2.shared.util.isEquivalent
1415

1516
@InternalReadiumApi
1617
public data class MediaOverlays(private val nodes: List<MediaOverlayNode> = listOf()) : Serializable {
@@ -21,11 +22,12 @@ public data class MediaOverlays(private val nodes: List<MediaOverlayNode> = list
2122

2223
private fun nodeForFragment(ref: Url?): MediaOverlayNode? = findNode(ref, this.nodes)
2324

25+
@OptIn(DelicateReadiumApi::class)
2426
private fun findNode(ref: Url?, inNodes: List<MediaOverlayNode>): MediaOverlayNode? {
2527
for (node in inNodes) {
2628
if (node.role.contains("section")) {
2729
return findNode(ref, node.children)
28-
} else if (ref == null || node.text == ref) {
30+
} else if (ref == null || node.text.isEquivalent(ref)) {
2931
return node
3032
}
3133
}
@@ -36,6 +38,7 @@ public data class MediaOverlays(private val nodes: List<MediaOverlayNode> = list
3638

3739
private fun nodeAfterFragment(ref: Url?): MediaOverlayNode? = findNextNode(ref, this.nodes).found
3840

41+
@OptIn(DelicateReadiumApi::class)
3942
private fun findNextNode(fragment: Url?, inNodes: List<MediaOverlayNode>): NextNodeResult {
4043
var prevNodeFoundFlag = false
4144
// For each node of the current scope...
@@ -55,7 +58,7 @@ public data class MediaOverlays(private val nodes: List<MediaOverlayNode> = list
5558
prevNodeFoundFlag = ret.prevFound
5659
}
5760
// If the node text refer to filename or that filename is null, return node
58-
else if (fragment == null || node.text == fragment) {
61+
else if (fragment == null || node.text.isEquivalent(fragment)) {
5962
prevNodeFoundFlag = true
6063
}
6164
}

readium/shared/src/main/java/org/readium/r2/shared/publication/Link.kt

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -261,13 +261,13 @@ public data class Link(
261261
* Returns the first [Link] with the given [href], or null if not found.
262262
*/
263263
public fun List<Link>.indexOfFirstWithHref(href: Url): Int? =
264-
indexOfFirst { it.url() == href }
264+
indexOfFirst { it.url().isEquivalent(href) }
265265
.takeUnless { it == -1 }
266266

267267
/**
268268
* Finds the first link matching the given HREF.
269269
*/
270-
public fun List<Link>.firstWithHref(href: Url): Link? = firstOrNull { it.url() == href }
270+
public fun List<Link>.firstWithHref(href: Url): Link? = firstOrNull { it.url().isEquivalent(href) }
271271

272272
/**
273273
* Finds the first link with the given relation.

readium/shared/src/main/java/org/readium/r2/shared/publication/Manifest.kt

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ package org.readium.r2.shared.publication
1313

1414
import org.json.JSONArray
1515
import org.json.JSONObject
16+
import org.readium.r2.shared.DelicateReadiumApi
1617
import org.readium.r2.shared.InternalReadiumApi
1718
import org.readium.r2.shared.JSONable
1819
import org.readium.r2.shared.extensions.optStringsFromArrayOrSingle
@@ -66,10 +67,11 @@ public data class Manifest(
6667
* If there's no match, tries again after removing any query parameter and anchor from the
6768
* given [href].
6869
*/
70+
@OptIn(DelicateReadiumApi::class)
6971
public fun linkWithHref(href: Url): Link? {
7072
fun List<Link>.deepLinkWithHref(href: Url): Link? {
7173
for (l in this) {
72-
if (l.url() == href) {
74+
if (l.url().normalize() == href) {
7375
return l
7476
} else {
7577
l.alternates.deepLinkWithHref(href)?.let { return it }
@@ -85,8 +87,9 @@ public data class Manifest(
8587
?: links.deepLinkWithHref(href)
8688
}
8789

88-
return find(href)
89-
?: find(href.removeFragment().removeQuery())
90+
val normalizedHref = href.normalize()
91+
return find(normalizedHref)
92+
?: find(normalizedHref.removeFragment().removeQuery())
9093
}
9194

9295
/**

0 commit comments

Comments
 (0)