diff --git a/NEWS b/NEWS index 5208f9085..74faa5bae 100644 --- a/NEWS +++ b/NEWS @@ -12,7 +12,11 @@ ver 0.22 (not yet released) - ffmpeg: new plugin based on FFmpeg's libavfilter library - hdcd: new plugin based on FFmpeg's "af_hdcd" for HDCD playback -ver 0.21.10 (not yet released) +ver 0.21.10 (2019/06/05) +* decoder + - opus: fix duplicate tags +* output + - httpd: reject some well-known URIs * fix crash bug (0.21.9 regression) ver 0.21.9 (2019/05/20) diff --git a/src/decoder/plugins/OpusReader.hxx b/src/decoder/plugins/OpusReader.hxx index 12d6d467e..5f944e920 100644 --- a/src/decoder/plugins/OpusReader.hxx +++ b/src/decoder/plugins/OpusReader.hxx @@ -1,5 +1,5 @@ /* - * Copyright 2003-2018 The Music Player Daemon Project + * Copyright 2003-2019 The Music Player Daemon Project * http://www.musicpd.org * * This program is free software; you can redistribute it and/or modify @@ -20,6 +20,8 @@ #ifndef MPD_OPUS_READER_HXX #define MPD_OPUS_READER_HXX +#include "util/StringView.hxx" + #include #include @@ -81,18 +83,16 @@ public: return ReadWord(length) && Skip(length); } - char *ReadString() { + StringView ReadString() { uint32_t length; - if (!ReadWord(length) || length >= 65536) + if (!ReadWord(length)) return nullptr; const char *src = (const char *)Read(length); if (src == nullptr) return nullptr; - char *dest = new char[length + 1]; - *std::copy_n(src, length, dest) = 0; - return dest; + return {src, length}; } }; diff --git a/src/decoder/plugins/OpusTags.cxx b/src/decoder/plugins/OpusTags.cxx index f4dce2810..c0a14fa89 100644 --- a/src/decoder/plugins/OpusTags.cxx +++ b/src/decoder/plugins/OpusTags.cxx @@ -24,6 +24,8 @@ #include "tag/ParseName.hxx" #include "ReplayGainInfo.hxx" +#include + #include #include #include @@ -91,18 +93,25 @@ ScanOpusTags(const void *data, size_t size, return false; while (n-- > 0) { - char *p = r.ReadString(); - if (p == nullptr) + const auto s = r.ReadString(); + if (s == nullptr) return false; - char *eq = strchr(p, '='); - if (eq != nullptr && eq > p) { - *eq = 0; + if (s.size >= 4096) + continue; - ScanOneOpusTag(p, eq + 1, rgi, handler); - } + const auto eq = s.Find('='); + if (eq == nullptr || eq == s.data) + continue; - delete[] p; + auto name = s, value = s; + name.SetEnd(eq); + value.MoveFront(eq + 1); + + const std::string name2(name.data, name.size); + const std::string value2(value.data, value.size); + + ScanOneOpusTag(name2.c_str(), value2.c_str(), rgi, handler); } return true; diff --git a/src/output/plugins/httpd/HttpdClient.cxx b/src/output/plugins/httpd/HttpdClient.cxx index db602b955..40435fae1 100644 --- a/src/output/plugins/httpd/HttpdClient.cxx +++ b/src/output/plugins/httpd/HttpdClient.cxx @@ -71,10 +71,10 @@ HttpdClient::HandleLine(const char *line) noexcept assert(state != State::RESPONSE); if (state == State::REQUEST) { - if (memcmp(line, "HEAD /", 6) == 0) { + if (strncmp(line, "HEAD /", 6) == 0) { line += 6; head_method = true; - } else if (memcmp(line, "GET /", 5) == 0) { + } else if (strncmp(line, "GET /", 5) == 0) { line += 5; } else { /* only GET is supported */ @@ -83,8 +83,19 @@ HttpdClient::HandleLine(const char *line) noexcept return false; } + /* blacklist some well-known request paths */ + if ((strncmp(line, "favicon.ico", 11) == 0 && + (line[11] == '\0' || line[11] == ' ')) || + (strncmp(line, "robots.txt", 10) == 0 && + (line[10] == '\0' || line[10] == ' ')) || + (strncmp(line, "sitemap.xml", 11) == 0 && + (line[11] == '\0' || line[11] == ' ')) || + (strncmp(line, ".well-known/", 12) == 0)) { + should_reject = true; + } + line = strchr(line, ' '); - if (line == nullptr || memcmp(line + 1, "HTTP/", 5) != 0) { + if (line == nullptr || strncmp(line + 1, "HTTP/", 5) != 0) { /* HTTP/0.9 without request headers */ if (head_method) @@ -129,14 +140,21 @@ HttpdClient::SendResponse() noexcept assert(state == State::RESPONSE); - if (metadata_requested) { + if (should_reject) { + response = + "HTTP/1.1 404 not found\r\n" + "Content-Type: text/plain\r\n" + "Connection: close\r\n" + "\r\n" + "404 not found"; + } else if (metadata_requested) { allocated = icy_server_metadata_header(httpd.name, httpd.genre, httpd.website, httpd.content_type, metaint); response = allocated.c_str(); - } else { /* revert to a normal HTTP request */ + } else { /* revert to a normal HTTP request */ snprintf(buffer, sizeof(buffer), "HTTP/1.1 200 OK\r\n" "Content-Type: %s\r\n" @@ -415,7 +433,7 @@ HttpdClient::OnSocketInput(void *data, size_t length) noexcept if (!SendResponse()) return InputResult::CLOSED; - if (head_method) { + if (head_method || should_reject) { LockClose(); return InputResult::CLOSED; } diff --git a/src/output/plugins/httpd/HttpdClient.hxx b/src/output/plugins/httpd/HttpdClient.hxx index 751d3f2c3..7977cf419 100644 --- a/src/output/plugins/httpd/HttpdClient.hxx +++ b/src/output/plugins/httpd/HttpdClient.hxx @@ -83,6 +83,11 @@ class HttpdClient final */ bool head_method = false; + /** + * Should we reject this request? + */ + bool should_reject = false; + /* ICY */ /**