From 3ef5185552cca45c648ea229725c1c0a5b7912a5 Mon Sep 17 00:00:00 2001 From: emeric Date: Thu, 19 Feb 2026 23:44:03 +0100 Subject: [PATCH] Subsonic API: always report the old protocol version when needed, to make DSub work again --- src/libs/subsonic/impl/RequestContext.cpp | 8 ++++-- src/libs/subsonic/impl/RequestContext.hpp | 4 ++- src/libs/subsonic/impl/SubsonicResource.cpp | 28 +++++++++------------ src/libs/subsonic/impl/SubsonicResource.hpp | 2 +- 4 files changed, 22 insertions(+), 20 deletions(-) diff --git a/src/libs/subsonic/impl/RequestContext.cpp b/src/libs/subsonic/impl/RequestContext.cpp index 8f8c5283..8ca811ac 100644 --- a/src/libs/subsonic/impl/RequestContext.cpp +++ b/src/libs/subsonic/impl/RequestContext.cpp @@ -43,10 +43,9 @@ namespace lms::api::subsonic } } // namespace - RequestContext::RequestContext(const Wt::Http::Request& request, db::Session& dbSession, db::ObjectPtr user, const SubsonicResourceConfig& config) + RequestContext::RequestContext(const Wt::Http::Request& request, db::Session& dbSession, const SubsonicResourceConfig& config) : _request{ request } , _dbSession{ dbSession } - , _user{ user } , _config{ config } , _clientName{ getMandatoryParameterAs(_request.getParameterMap(), "c") } , _clientProtocolVersion{ getMandatoryParameterAs(_request.getParameterMap(), "v") } @@ -74,6 +73,11 @@ namespace lms::api::subsonic return _dbSession; } + void RequestContext::setUser(const db::ObjectPtr& user) + { + _user = user; + } + db::ObjectPtr RequestContext::getUser() const { return _user; diff --git a/src/libs/subsonic/impl/RequestContext.hpp b/src/libs/subsonic/impl/RequestContext.hpp index 7e295756..c5cc1568 100644 --- a/src/libs/subsonic/impl/RequestContext.hpp +++ b/src/libs/subsonic/impl/RequestContext.hpp @@ -42,7 +42,7 @@ namespace lms::api::subsonic class RequestContext { public: - RequestContext(const Wt::Http::Request& request, db::Session& dbSession, db::ObjectPtr user, const SubsonicResourceConfig& config); + RequestContext(const Wt::Http::Request& request, db::Session& dbSession, const SubsonicResourceConfig& config); ~RequestContext(); RequestContext(const RequestContext&) = delete; RequestContext& operator=(const RequestContext&) = delete; @@ -53,6 +53,8 @@ namespace lms::api::subsonic std::istream& getBody() const; db::Session& getDbSession(); + + void setUser(const db::ObjectPtr& user); db::ObjectPtr getUser() const; std::string getClientIpAddr() const; diff --git a/src/libs/subsonic/impl/SubsonicResource.cpp b/src/libs/subsonic/impl/SubsonicResource.cpp index fad49323..e9d5f7fe 100644 --- a/src/libs/subsonic/impl/SubsonicResource.cpp +++ b/src/libs/subsonic/impl/SubsonicResource.cpp @@ -297,6 +297,8 @@ namespace lms::api::subsonic if (core::stringUtils::stringEndsWith(requestPath, ".view")) requestPath.resize(requestPath.length() - 5); + RequestContext requestContext{ request, _db.getTLSSession(), _config }; + // First check for media retrieval endpoints auto itStreamHandler{ mediaRetrievalHandlers.find(requestPath) }; if (itStreamHandler != mediaRetrievalHandlers.end()) @@ -304,7 +306,7 @@ namespace lms::api::subsonic try { LMS_SCOPED_TRACE_OVERVIEW("Subsonic", itStreamHandler->first); - handleMediaRetrievalRequest(itStreamHandler->second, request, response); + handleMediaRetrievalRequest(itStreamHandler->second, requestContext, request, response); LMS_LOG(API_SUBSONIC, DEBUG, "Request " << requestId << " '" << requestPath << "' handled!"); } catch (const Error& e) @@ -315,11 +317,7 @@ namespace lms::api::subsonic return; } - // Optional parameters - const ResponseFormat format{ getParameterAs(request.getParameterMap(), "f").value_or("xml") == "json" ? ResponseFormat::json : ResponseFormat::xml }; - - ProtocolVersion protocolVersion{ defaultServerProtocolVersion }; - + // Now check other endpoints try { if (auto itEntryPoint{ requestEntryPoints.find(requestPath) }; itEntryPoint != requestEntryPoints.end()) @@ -331,11 +329,9 @@ namespace lms::api::subsonic { user = getUserFromUserId(_db.getTLSSession(), authenticateUser(request)); checkUserTypeIsAllowed(user, itEntryPoint->second.allowedUserTypes); + requestContext.setUser(user); } - RequestContext requestContext{ request, _db.getTLSSession(), user, _config }; - protocolVersion = requestContext.getServerProtocolVersion(); - const Response resp{ [&] { LMS_SCOPED_TRACE_DETAILED("Subsonic", "HandleRequest"); return itEntryPoint->second.func(requestContext); @@ -344,8 +340,8 @@ namespace lms::api::subsonic { LMS_SCOPED_TRACE_DETAILED("Subsonic", "WriteResponse"); - resp.write(response.out(), format); - response.setMimeType(std::string{ ResponseFormatToMimeType(format) }); + resp.write(response.out(), requestContext.getResponseFormat()); + response.setMimeType(std::string{ ResponseFormatToMimeType(requestContext.getResponseFormat()) }); } LMS_LOG(API_SUBSONIC, DEBUG, "Request " << requestId << " '" << requestPath << "' handled!"); @@ -361,13 +357,13 @@ namespace lms::api::subsonic catch (const Error& e) { LMS_LOG(API_SUBSONIC, ERROR, "Error while processing request '" << requestPath << "'" << ", params = [" << parameterMapToDebugString(request.getParameterMap()) << "]" << ", code = " << static_cast(e.getCode()) << ", msg = '" << e.getMessage() << "'"); - Response resp{ Response::createFailedResponse(protocolVersion, e) }; - resp.write(response.out(), format); - response.setMimeType(std::string{ ResponseFormatToMimeType(format) }); + Response resp{ Response::createFailedResponse(requestContext.getServerProtocolVersion(), e) }; + resp.write(response.out(), requestContext.getResponseFormat()); + response.setMimeType(std::string{ ResponseFormatToMimeType(requestContext.getResponseFormat()) }); } } - void SubsonicResource::handleMediaRetrievalRequest(MediaRetrievalHandlerFunc handler, const Wt::Http::Request& request, Wt::Http::Response& response) + void SubsonicResource::handleMediaRetrievalRequest(const MediaRetrievalHandlerFunc& handler, RequestContext& requestContext, const Wt::Http::Request& request, Wt::Http::Response& response) { try { @@ -377,7 +373,7 @@ namespace lms::api::subsonic if (!request.continuation()) user = getUserFromUserId(_db.getTLSSession(), authenticateUser(request)); - RequestContext requestContext{ request, _db.getTLSSession(), user, _config }; + requestContext.setUser(user); handler(requestContext, request, response); } diff --git a/src/libs/subsonic/impl/SubsonicResource.hpp b/src/libs/subsonic/impl/SubsonicResource.hpp index 32bf4318..f65c92c3 100644 --- a/src/libs/subsonic/impl/SubsonicResource.hpp +++ b/src/libs/subsonic/impl/SubsonicResource.hpp @@ -44,7 +44,7 @@ namespace lms::api::subsonic void handleRequest(const Wt::Http::Request& request, Wt::Http::Response& response) override; using MediaRetrievalHandlerFunc = std::function; - void handleMediaRetrievalRequest(MediaRetrievalHandlerFunc handler, const Wt::Http::Request& request, Wt::Http::Response& response); + void handleMediaRetrievalRequest(const MediaRetrievalHandlerFunc& handler, RequestContext& requestContext, const Wt::Http::Request& request, Wt::Http::Response& response); db::UserId authenticateUser(const Wt::Http::Request& request);