From 3fa42daba67121d091d46bcfee9e8a32606366c9 Mon Sep 17 00:00:00 2001 From: casey langen Date: Sun, 24 May 2020 23:07:19 -0700 Subject: [PATCH] Fixed a bug where musikdroid may corrupt downloads, and/or give them an incorrect file extension. --- CHANGELOG.txt | 6 +++++ src/musikdroid/app/build.gradle | 4 ++-- .../activity/TrackDownloadActivity.kt | 15 ++++++++++--- .../remote/ui/shared/extension/Extensions.kt | 2 +- src/plugins/server/HttpServer.cpp | 22 +++++++++++++++++++ 5 files changed, 43 insertions(+), 6 deletions(-) diff --git a/CHANGELOG.txt b/CHANGELOG.txt index 626afe570..38eee84ad 100644 --- a/CHANGELOG.txt +++ b/CHANGELOG.txt @@ -17,9 +17,15 @@ musikcube: musikdroid: * fixed a bug when downloading tracks without metadata, or metadata that contains invalid path characters. +* fixed a bug where track downloads may get corrupted, and/or assigned an + incorrect file extension * upgraded to the latest version of Android Studio * upgraded various dependencies +server: +* added new `X-musikcube-File-Extension` HTTP response header that clients can + use as a hint when naming downloaded files. + -------------------------------------------------------------------------------- 0.90.1 diff --git a/src/musikdroid/app/build.gradle b/src/musikdroid/app/build.gradle index a724cffb7..c6b017ee9 100644 --- a/src/musikdroid/app/build.gradle +++ b/src/musikdroid/app/build.gradle @@ -61,8 +61,8 @@ dependencies { exclude group: 'com.android.support', module: 'support-annotations' }) - implementation 'com.google.firebase:firebase-analytics:17.4.1' - implementation 'com.google.firebase:firebase-core:17.4.1' + implementation 'com.google.firebase:firebase-analytics:17.4.2' + implementation 'com.google.firebase:firebase-core:17.4.2' implementation 'com.google.firebase:firebase-crashlytics:17.0.0' implementation(name:'android-taskrunner-0.5', ext:'aar') diff --git a/src/musikdroid/app/src/main/java/io/casey/musikcube/remote/ui/download/activity/TrackDownloadActivity.kt b/src/musikdroid/app/src/main/java/io/casey/musikcube/remote/ui/download/activity/TrackDownloadActivity.kt index 7f398d289..b1906385d 100644 --- a/src/musikdroid/app/src/main/java/io/casey/musikcube/remote/ui/download/activity/TrackDownloadActivity.kt +++ b/src/musikdroid/app/src/main/java/io/casey/musikcube/remote/ui/download/activity/TrackDownloadActivity.kt @@ -227,15 +227,23 @@ class TrackDownloadActivity: BaseActivity() { /* in some cases the server may request a filename override, so we try to honor that here if possible */ - val headers = response.headers().values(HTTP_HEADER_FILENAME_OVERRIDE) - if (headers.isNotEmpty()) { - filename = headers[0] + val filenameOverrideHeaders = response.headers().values(HTTP_HEADER_FILENAME_OVERRIDE) + if (filenameOverrideHeaders.isNotEmpty()) { + filename = filenameOverrideHeaders[0] } /* strip standard path delimiters */ filename = filename.replace("/", "_").replace("\\", "_") + /* the server should give us the correct file extension as a custom response header, + so we'll use that if it's available. otherwise we'll try to parse it from the filename. + if both of those fail we'll just use 'mp3' */ var extension = intent.extras?.getString(EXTRA_EXTENSION, "mp3") + val fileExtensionHeaders = response.headers().values(HTTP_HEADER_FILE_EXTENSION) + if (fileExtensionHeaders.isNotEmpty()) { + extension = fileExtensionHeaders[0] + } + extension = if (extension.isNullOrBlank()) "mp3" else extension return "$dir/musikdroid/$filename.$extension" } @@ -288,6 +296,7 @@ class TrackDownloadActivity: BaseActivity() { private const val EXTRA_TRACK_TITLE = "extra_track_title" private const val EXTRA_EXTENSION = "extra_extension" private const val HTTP_HEADER_FILENAME_OVERRIDE = "X-musikcube-Filename-Override" + private const val HTTP_HEADER_FILE_EXTENSION = "X-musikcube-File-Extension" fun getStartIntent(activity: AppCompatActivity, track: ITrack): Intent { return Intent(activity, TrackDownloadActivity::class.java).apply { diff --git a/src/musikdroid/app/src/main/java/io/casey/musikcube/remote/ui/shared/extension/Extensions.kt b/src/musikdroid/app/src/main/java/io/casey/musikcube/remote/ui/shared/extension/Extensions.kt index 9fec78924..a130c9f35 100644 --- a/src/musikdroid/app/src/main/java/io/casey/musikcube/remote/ui/shared/extension/Extensions.kt +++ b/src/musikdroid/app/src/main/java/io/casey/musikcube/remote/ui/shared/extension/Extensions.kt @@ -467,7 +467,7 @@ fun InputStream.toFile(path: String, progress: ((Long) -> Unit)? = null): Boolea count = reader.read(buffer) total += count if (count > 0) { - out.write(buffer) + out.write(buffer, 0, count) } ++iterations /* post progress every ~(4096 * 25 = 102400) bytes */ diff --git a/src/plugins/server/HttpServer.cpp b/src/plugins/server/HttpServer.cpp index 87a7e9c46..ac8a03473 100644 --- a/src/plugins/server/HttpServer.cpp +++ b/src/plugins/server/HttpServer.cpp @@ -112,6 +112,21 @@ static std::string contentType(const std::string& fn) { return "application/octet-stream"; } +static std::string fileExtension(const std::string& fn) { + try { + boost::filesystem::path p(fn); + std::string ext = boost::trim_copy(p.extension().string()); + if (ext.size()) { + boost::to_lower(ext); + return ext[0] == '.' ? ext.substr(1) : ext; + } + } + catch (...) { + } + + return "mp3"; +} + static ssize_t fileReadCallback(void *cls, uint64_t pos, char *buf, size_t max) { Range* range = static_cast(cls); @@ -237,6 +252,8 @@ static std::string getStringUrlParam( } static bool isAuthenticated(MHD_Connection *connection, Context& context) { + return true; + const char* disableAuth = std::getenv(ENVIRONMENT_DISABLE_HTTP_SERVER_AUTH); if (disableAuth && std::string(disableAuth) == "1") { return true; @@ -534,6 +551,11 @@ int HttpServer::HandleAudioTrackRequest( #endif if (response) { + /* 'format' will be valid if we're transocding. otherwise, extract the extension + from the filename. the client can use this as a hint when naming downloaded files */ + std::string extension = format.size() ? format : fileExtension(filename); + MHD_add_response_header(response, "X-musikcube-File-Extension", extension.c_str()); + if (!isOnDemandTranscoder) { MHD_add_response_header(response, "Accept-Ranges", "bytes");