diff --git a/src/output/plugins/httpd/HttpdClient.cxx b/src/output/plugins/httpd/HttpdClient.cxx index 5096865f6..40775157b 100644 --- a/src/output/plugins/httpd/HttpdClient.cxx +++ b/src/output/plugins/httpd/HttpdClient.cxx @@ -3,19 +3,19 @@ #include "HttpdClient.hxx" #include "HttpdInternal.hxx" -#include "util/ASCII.hxx" #include "util/AllocatedString.hxx" #include "Page.hxx" #include "IcyMetaDataServer.hxx" #include "net/SocketError.hxx" #include "net/UniqueSocketDescriptor.hxx" #include "util/SpanCast.hxx" +#include "util/StringCompare.hxx" +#include "util/StringSplit.hxx" #include "Log.hxx" #include #include -#include using std::string_view_literals::operator""sv; @@ -51,36 +51,31 @@ HttpdClient::BeginResponse() noexcept } bool -HttpdClient::HandleLine(const char *line) noexcept +HttpdClient::HandleLine(std::string_view line) noexcept { assert(state != State::RESPONSE); if (state == State::REQUEST) { - if (strncmp(line, "HEAD /", 6) == 0) { - line += 6; + if (SkipPrefix(line, "HEAD /"sv)) { head_method = true; - } else if (strncmp(line, "GET /", 5) == 0) { - line += 5; - } else { + } else if (!SkipPrefix(line, "GET /"sv)) { /* only GET is supported */ LogWarning(httpd_output_domain, "malformed request line from client"); return false; } + const auto [uri, rest] = Split(line, ' '); + /* 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)) { + if (uri == "favicon.ico"sv || + uri == "robots.txt"sv || + uri == "sitemap.xml"sv || + uri.starts_with(".well-known/"sv)) { should_reject = true; } - line = std::strchr(line, ' '); - if (line == nullptr || strncmp(line + 1, "HTTP/", 5) != 0) { + if (!rest.starts_with("HTTP/"sv)) { /* HTTP/0.9 without request headers */ if (head_method) @@ -94,15 +89,15 @@ HttpdClient::HandleLine(const char *line) noexcept state = State::HEADERS; return true; } else { - if (*line == 0) { + if (line.empty()) { /* empty line: request is finished */ BeginResponse(); return true; } - if (StringEqualsCaseASCII(line, "Icy-MetaData: 1", 15) || - StringEqualsCaseASCII(line, "Icy-MetaData:1", 14)) { + if (StringIsEqualIgnoreCase(line, "Icy-MetaData: 1"sv) || + StringIsEqualIgnoreCase(line, "Icy-MetaData:1"sv)) { /* Send icy metadata */ metadata_requested = metadata_supported; return true; @@ -379,7 +374,7 @@ HttpdClient::OnSocketReady(unsigned flags) noexcept } BufferedSocket::InputResult -HttpdClient::OnSocketInput(std::span src) noexcept +HttpdClient::OnSocketInput(std::span _src) noexcept { if (state == State::RESPONSE) { LogWarning(httpd_output_domain, @@ -388,18 +383,15 @@ HttpdClient::OnSocketInput(std::span src) noexcept return InputResult::CLOSED; } - char *line = (char *)src.data(); - char *newline = (char *)std::memchr(line, '\n', src.size()); - if (newline == nullptr) + const auto src = ToStringView(_src); + auto [line, rest] = Split(src, '\n'); + if (rest.data() == nullptr) return InputResult::MORE; - ConsumeInput(newline + 1 - line); + ConsumeInput(line.size() + 1); - if (newline > line && newline[-1] == '\r') - --newline; - - /* terminate the string at the end of the line */ - *newline = 0; + if (line.ends_with('\r')) + line.remove_suffix(1); if (!HandleLine(line)) { LockClose(); diff --git a/src/output/plugins/httpd/HttpdClient.hxx b/src/output/plugins/httpd/HttpdClient.hxx index 527342dd5..283ebac8e 100644 --- a/src/output/plugins/httpd/HttpdClient.hxx +++ b/src/output/plugins/httpd/HttpdClient.hxx @@ -1,8 +1,7 @@ // SPDX-License-Identifier: GPL-2.0-or-later // Copyright The Music Player Daemon Project -#ifndef MPD_OUTPUT_HTTPD_CLIENT_HXX -#define MPD_OUTPUT_HTTPD_CLIENT_HXX +#pragma once #include "Page.hxx" #include "event/BufferedSocket.hxx" @@ -11,6 +10,7 @@ #include #include #include +#include class UniqueSocketDescriptor; class HttpdOutput; @@ -143,7 +143,7 @@ public: /** * Handle a line of the HTTP request. */ - bool HandleLine(const char *line) noexcept; + bool HandleLine(std::string_view line) noexcept; /** * Switch the client to #State::RESPONSE. @@ -185,5 +185,3 @@ protected: void OnSocketError(std::exception_ptr ep) noexcept override; void OnSocketClosed() noexcept override; }; - -#endif