Subsonic API: always report the old protocol version when needed, to make DSub work again

This commit is contained in:
emeric
2026-02-19 23:44:03 +01:00
parent f12b2f673d
commit 3ef5185552
4 changed files with 22 additions and 20 deletions
+6 -2
View File
@@ -43,10 +43,9 @@ namespace lms::api::subsonic
} }
} // namespace } // namespace
RequestContext::RequestContext(const Wt::Http::Request& request, db::Session& dbSession, db::ObjectPtr<db::User> user, const SubsonicResourceConfig& config) RequestContext::RequestContext(const Wt::Http::Request& request, db::Session& dbSession, const SubsonicResourceConfig& config)
: _request{ request } : _request{ request }
, _dbSession{ dbSession } , _dbSession{ dbSession }
, _user{ user }
, _config{ config } , _config{ config }
, _clientName{ getMandatoryParameterAs<std::string>(_request.getParameterMap(), "c") } , _clientName{ getMandatoryParameterAs<std::string>(_request.getParameterMap(), "c") }
, _clientProtocolVersion{ getMandatoryParameterAs<ProtocolVersion>(_request.getParameterMap(), "v") } , _clientProtocolVersion{ getMandatoryParameterAs<ProtocolVersion>(_request.getParameterMap(), "v") }
@@ -74,6 +73,11 @@ namespace lms::api::subsonic
return _dbSession; return _dbSession;
} }
void RequestContext::setUser(const db::ObjectPtr<db::User>& user)
{
_user = user;
}
db::ObjectPtr<db::User> RequestContext::getUser() const db::ObjectPtr<db::User> RequestContext::getUser() const
{ {
return _user; return _user;
+3 -1
View File
@@ -42,7 +42,7 @@ namespace lms::api::subsonic
class RequestContext class RequestContext
{ {
public: public:
RequestContext(const Wt::Http::Request& request, db::Session& dbSession, db::ObjectPtr<db::User> user, const SubsonicResourceConfig& config); RequestContext(const Wt::Http::Request& request, db::Session& dbSession, const SubsonicResourceConfig& config);
~RequestContext(); ~RequestContext();
RequestContext(const RequestContext&) = delete; RequestContext(const RequestContext&) = delete;
RequestContext& operator=(const RequestContext&) = delete; RequestContext& operator=(const RequestContext&) = delete;
@@ -53,6 +53,8 @@ namespace lms::api::subsonic
std::istream& getBody() const; std::istream& getBody() const;
db::Session& getDbSession(); db::Session& getDbSession();
void setUser(const db::ObjectPtr<db::User>& user);
db::ObjectPtr<db::User> getUser() const; db::ObjectPtr<db::User> getUser() const;
std::string getClientIpAddr() const; std::string getClientIpAddr() const;
+12 -16
View File
@@ -297,6 +297,8 @@ namespace lms::api::subsonic
if (core::stringUtils::stringEndsWith(requestPath, ".view")) if (core::stringUtils::stringEndsWith(requestPath, ".view"))
requestPath.resize(requestPath.length() - 5); requestPath.resize(requestPath.length() - 5);
RequestContext requestContext{ request, _db.getTLSSession(), _config };
// First check for media retrieval endpoints // First check for media retrieval endpoints
auto itStreamHandler{ mediaRetrievalHandlers.find(requestPath) }; auto itStreamHandler{ mediaRetrievalHandlers.find(requestPath) };
if (itStreamHandler != mediaRetrievalHandlers.end()) if (itStreamHandler != mediaRetrievalHandlers.end())
@@ -304,7 +306,7 @@ namespace lms::api::subsonic
try try
{ {
LMS_SCOPED_TRACE_OVERVIEW("Subsonic", itStreamHandler->first); 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!"); LMS_LOG(API_SUBSONIC, DEBUG, "Request " << requestId << " '" << requestPath << "' handled!");
} }
catch (const Error& e) catch (const Error& e)
@@ -315,11 +317,7 @@ namespace lms::api::subsonic
return; return;
} }
// Optional parameters // Now check other endpoints
const ResponseFormat format{ getParameterAs<std::string>(request.getParameterMap(), "f").value_or("xml") == "json" ? ResponseFormat::json : ResponseFormat::xml };
ProtocolVersion protocolVersion{ defaultServerProtocolVersion };
try try
{ {
if (auto itEntryPoint{ requestEntryPoints.find(requestPath) }; itEntryPoint != requestEntryPoints.end()) if (auto itEntryPoint{ requestEntryPoints.find(requestPath) }; itEntryPoint != requestEntryPoints.end())
@@ -331,11 +329,9 @@ namespace lms::api::subsonic
{ {
user = getUserFromUserId(_db.getTLSSession(), authenticateUser(request)); user = getUserFromUserId(_db.getTLSSession(), authenticateUser(request));
checkUserTypeIsAllowed(user, itEntryPoint->second.allowedUserTypes); checkUserTypeIsAllowed(user, itEntryPoint->second.allowedUserTypes);
requestContext.setUser(user);
} }
RequestContext requestContext{ request, _db.getTLSSession(), user, _config };
protocolVersion = requestContext.getServerProtocolVersion();
const Response resp{ [&] { const Response resp{ [&] {
LMS_SCOPED_TRACE_DETAILED("Subsonic", "HandleRequest"); LMS_SCOPED_TRACE_DETAILED("Subsonic", "HandleRequest");
return itEntryPoint->second.func(requestContext); return itEntryPoint->second.func(requestContext);
@@ -344,8 +340,8 @@ namespace lms::api::subsonic
{ {
LMS_SCOPED_TRACE_DETAILED("Subsonic", "WriteResponse"); LMS_SCOPED_TRACE_DETAILED("Subsonic", "WriteResponse");
resp.write(response.out(), format); resp.write(response.out(), requestContext.getResponseFormat());
response.setMimeType(std::string{ ResponseFormatToMimeType(format) }); response.setMimeType(std::string{ ResponseFormatToMimeType(requestContext.getResponseFormat()) });
} }
LMS_LOG(API_SUBSONIC, DEBUG, "Request " << requestId << " '" << requestPath << "' handled!"); LMS_LOG(API_SUBSONIC, DEBUG, "Request " << requestId << " '" << requestPath << "' handled!");
@@ -361,13 +357,13 @@ namespace lms::api::subsonic
catch (const Error& e) catch (const Error& e)
{ {
LMS_LOG(API_SUBSONIC, ERROR, "Error while processing request '" << requestPath << "'" << ", params = [" << parameterMapToDebugString(request.getParameterMap()) << "]" << ", code = " << static_cast<int>(e.getCode()) << ", msg = '" << e.getMessage() << "'"); LMS_LOG(API_SUBSONIC, ERROR, "Error while processing request '" << requestPath << "'" << ", params = [" << parameterMapToDebugString(request.getParameterMap()) << "]" << ", code = " << static_cast<int>(e.getCode()) << ", msg = '" << e.getMessage() << "'");
Response resp{ Response::createFailedResponse(protocolVersion, e) }; Response resp{ Response::createFailedResponse(requestContext.getServerProtocolVersion(), e) };
resp.write(response.out(), format); resp.write(response.out(), requestContext.getResponseFormat());
response.setMimeType(std::string{ ResponseFormatToMimeType(format) }); 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 try
{ {
@@ -377,7 +373,7 @@ namespace lms::api::subsonic
if (!request.continuation()) if (!request.continuation())
user = getUserFromUserId(_db.getTLSSession(), authenticateUser(request)); user = getUserFromUserId(_db.getTLSSession(), authenticateUser(request));
RequestContext requestContext{ request, _db.getTLSSession(), user, _config }; requestContext.setUser(user);
handler(requestContext, request, response); handler(requestContext, request, response);
} }
+1 -1
View File
@@ -44,7 +44,7 @@ namespace lms::api::subsonic
void handleRequest(const Wt::Http::Request& request, Wt::Http::Response& response) override; void handleRequest(const Wt::Http::Request& request, Wt::Http::Response& response) override;
using MediaRetrievalHandlerFunc = std::function<void(RequestContext&, const Wt::Http::Request&, Wt::Http::Response&)>; using MediaRetrievalHandlerFunc = std::function<void(RequestContext&, const Wt::Http::Request&, Wt::Http::Response&)>;
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); db::UserId authenticateUser(const Wt::Http::Request& request);