Skip to content

Fix data race in OPDS1Parser #529

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Jan 8, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,12 @@ All notable changes to this project will be documented in this file. Take a look

* The default `ZIPArchiveOpener` is now using ZIPFoundation instead of Minizip, with improved performances when reading ranges of `stored` ZIP entries.

### Fixed

#### OPDS

* Fixed a data race in the OPDS 1 parser.


## [3.0.0-beta.1]

Expand Down
20 changes: 7 additions & 13 deletions Sources/OPDS/OPDS1Parser.swift
Original file line number Diff line number Diff line change
Expand Up @@ -28,14 +28,10 @@ struct MimeTypeParameters {
}

public class OPDS1Parser: Loggable {
static var feedURL: URL?

/// Parse an OPDS feed or publication.
/// Feed can only be v1 (XML).
/// - parameter url: The feed URL
public static func parseURL(url: URL, completion: @escaping (ParseData?, Error?) -> Void) {
feedURL = url

URLSession.shared.dataTask(with: url) { data, response, error in
guard let data = data, let response = response else {
completion(nil, error ?? OPDSParserError.documentNotFound)
Expand All @@ -58,19 +54,17 @@ public class OPDS1Parser: Loggable {
/// - parameter response: The response payload
/// - Returns: The intermediate structure of type ParseData
public static func parse(xmlData: Data, url: URL, response: URLResponse) throws -> ParseData {
feedURL = url

var parseData = ParseData(url: url, response: response, version: .OPDS1)

let xmlDocument = try XMLDocument(data: xmlData)

if xmlDocument.root?.tag == "feed" {
// Feed
parseData.feed = try? parse(document: xmlDocument)
parseData.feed = try? parse(document: xmlDocument, feedURL: url)
} else if xmlDocument.root?.tag == "entry" {
// Publication only
do {
parseData.publication = try parseEntry(document: xmlDocument)
parseData.publication = try parseEntry(document: xmlDocument, feedURL: url)
} catch {
log(.warning, "Failed to parse Publication at \(url)")
}
Expand All @@ -85,7 +79,7 @@ public class OPDS1Parser: Loggable {
/// Feed can only be v1 (XML).
/// - parameter document: The XMLDocument data
/// - Returns: The resulting Feed
public static func parse(document: ReadiumFuzi.XMLDocument) throws -> Feed {
private static func parse(document: ReadiumFuzi.XMLDocument, feedURL: URL) throws -> Feed {
document.definePrefix("thr", forNamespace: "http://purl.org/syndication/thread/1.0")
document.definePrefix("dcterms", forNamespace: "http://purl.org/dc/terms/")
document.definePrefix("opds", forNamespace: "http://opds-spec.org/2010/catalog")
Expand Down Expand Up @@ -136,7 +130,7 @@ public class OPDS1Parser: Loggable {
}

if !isNavigation {
if let publication = parseEntry(entry: entry) {
if let publication = parseEntry(entry: entry, feedURL: feedURL) {
// Checking if this publication need to go into a group or in publications.
if let collectionLink = collectionLink {
addPublicationInGroup(feed, publication, collectionLink)
Expand Down Expand Up @@ -218,11 +212,11 @@ public class OPDS1Parser: Loggable {
/// Publication can only be v1 (XML).
/// - parameter document: The XMLDocument data
/// - Returns: The resulting Publication
public static func parseEntry(document: ReadiumFuzi.XMLDocument) throws -> Publication? {
public static func parseEntry(document: ReadiumFuzi.XMLDocument, feedURL: URL) throws -> Publication? {
guard let root = document.root else {
throw OPDS1ParserError.rootNotFound
}
return parseEntry(entry: root)
return parseEntry(entry: root, feedURL: feedURL)
}

/// Fetch an Open Search template from an OPDS feed.
Expand Down Expand Up @@ -297,7 +291,7 @@ public class OPDS1Parser: Loggable {
return MimeTypeParameters(type: type, parameters: params)
}

static func parseEntry(entry: ReadiumFuzi.XMLElement) -> Publication? {
static func parseEntry(entry: ReadiumFuzi.XMLElement, feedURL: URL) -> Publication? {
// Shortcuts to get tag(s)' string value.
func tag(_ name: String) -> String? {
entry.firstChild(tag: name)?.stringValue
Expand Down