output/httpd/Client: pass std::string_view to HandleLine()

This commit is contained in:
Max Kellermann 2024-04-03 20:33:51 +02:00
parent 1e5c37ee78
commit 91ca502e10
2 changed files with 25 additions and 35 deletions

View File

@ -3,19 +3,19 @@
#include "HttpdClient.hxx" #include "HttpdClient.hxx"
#include "HttpdInternal.hxx" #include "HttpdInternal.hxx"
#include "util/ASCII.hxx"
#include "util/AllocatedString.hxx" #include "util/AllocatedString.hxx"
#include "Page.hxx" #include "Page.hxx"
#include "IcyMetaDataServer.hxx" #include "IcyMetaDataServer.hxx"
#include "net/SocketError.hxx" #include "net/SocketError.hxx"
#include "net/UniqueSocketDescriptor.hxx" #include "net/UniqueSocketDescriptor.hxx"
#include "util/SpanCast.hxx" #include "util/SpanCast.hxx"
#include "util/StringCompare.hxx"
#include "util/StringSplit.hxx"
#include "Log.hxx" #include "Log.hxx"
#include <fmt/core.h> #include <fmt/core.h>
#include <cassert> #include <cassert>
#include <cstring>
using std::string_view_literals::operator""sv; using std::string_view_literals::operator""sv;
@ -51,36 +51,31 @@ HttpdClient::BeginResponse() noexcept
} }
bool bool
HttpdClient::HandleLine(const char *line) noexcept HttpdClient::HandleLine(std::string_view line) noexcept
{ {
assert(state != State::RESPONSE); assert(state != State::RESPONSE);
if (state == State::REQUEST) { if (state == State::REQUEST) {
if (strncmp(line, "HEAD /", 6) == 0) { if (SkipPrefix(line, "HEAD /"sv)) {
line += 6;
head_method = true; head_method = true;
} else if (strncmp(line, "GET /", 5) == 0) { } else if (!SkipPrefix(line, "GET /"sv)) {
line += 5;
} else {
/* only GET is supported */ /* only GET is supported */
LogWarning(httpd_output_domain, LogWarning(httpd_output_domain,
"malformed request line from client"); "malformed request line from client");
return false; return false;
} }
const auto [uri, rest] = Split(line, ' ');
/* blacklist some well-known request paths */ /* blacklist some well-known request paths */
if ((strncmp(line, "favicon.ico", 11) == 0 && if (uri == "favicon.ico"sv ||
(line[11] == '\0' || line[11] == ' ')) || uri == "robots.txt"sv ||
(strncmp(line, "robots.txt", 10) == 0 && uri == "sitemap.xml"sv ||
(line[10] == '\0' || line[10] == ' ')) || uri.starts_with(".well-known/"sv)) {
(strncmp(line, "sitemap.xml", 11) == 0 &&
(line[11] == '\0' || line[11] == ' ')) ||
(strncmp(line, ".well-known/", 12) == 0)) {
should_reject = true; should_reject = true;
} }
line = std::strchr(line, ' '); if (!rest.starts_with("HTTP/"sv)) {
if (line == nullptr || strncmp(line + 1, "HTTP/", 5) != 0) {
/* HTTP/0.9 without request headers */ /* HTTP/0.9 without request headers */
if (head_method) if (head_method)
@ -94,15 +89,15 @@ HttpdClient::HandleLine(const char *line) noexcept
state = State::HEADERS; state = State::HEADERS;
return true; return true;
} else { } else {
if (*line == 0) { if (line.empty()) {
/* empty line: request is finished */ /* empty line: request is finished */
BeginResponse(); BeginResponse();
return true; return true;
} }
if (StringEqualsCaseASCII(line, "Icy-MetaData: 1", 15) || if (StringIsEqualIgnoreCase(line, "Icy-MetaData: 1"sv) ||
StringEqualsCaseASCII(line, "Icy-MetaData:1", 14)) { StringIsEqualIgnoreCase(line, "Icy-MetaData:1"sv)) {
/* Send icy metadata */ /* Send icy metadata */
metadata_requested = metadata_supported; metadata_requested = metadata_supported;
return true; return true;
@ -379,7 +374,7 @@ HttpdClient::OnSocketReady(unsigned flags) noexcept
} }
BufferedSocket::InputResult BufferedSocket::InputResult
HttpdClient::OnSocketInput(std::span<std::byte> src) noexcept HttpdClient::OnSocketInput(std::span<std::byte> _src) noexcept
{ {
if (state == State::RESPONSE) { if (state == State::RESPONSE) {
LogWarning(httpd_output_domain, LogWarning(httpd_output_domain,
@ -388,18 +383,15 @@ HttpdClient::OnSocketInput(std::span<std::byte> src) noexcept
return InputResult::CLOSED; return InputResult::CLOSED;
} }
char *line = (char *)src.data(); const auto src = ToStringView(_src);
char *newline = (char *)std::memchr(line, '\n', src.size()); auto [line, rest] = Split(src, '\n');
if (newline == nullptr) if (rest.data() == nullptr)
return InputResult::MORE; return InputResult::MORE;
ConsumeInput(newline + 1 - line); ConsumeInput(line.size() + 1);
if (newline > line && newline[-1] == '\r') if (line.ends_with('\r'))
--newline; line.remove_suffix(1);
/* terminate the string at the end of the line */
*newline = 0;
if (!HandleLine(line)) { if (!HandleLine(line)) {
LockClose(); LockClose();

View File

@ -1,8 +1,7 @@
// SPDX-License-Identifier: GPL-2.0-or-later // SPDX-License-Identifier: GPL-2.0-or-later
// Copyright The Music Player Daemon Project // Copyright The Music Player Daemon Project
#ifndef MPD_OUTPUT_HTTPD_CLIENT_HXX #pragma once
#define MPD_OUTPUT_HTTPD_CLIENT_HXX
#include "Page.hxx" #include "Page.hxx"
#include "event/BufferedSocket.hxx" #include "event/BufferedSocket.hxx"
@ -11,6 +10,7 @@
#include <cstddef> #include <cstddef>
#include <list> #include <list>
#include <queue> #include <queue>
#include <string_view>
class UniqueSocketDescriptor; class UniqueSocketDescriptor;
class HttpdOutput; class HttpdOutput;
@ -143,7 +143,7 @@ public:
/** /**
* Handle a line of the HTTP request. * 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. * Switch the client to #State::RESPONSE.
@ -185,5 +185,3 @@ protected:
void OnSocketError(std::exception_ptr ep) noexcept override; void OnSocketError(std::exception_ptr ep) noexcept override;
void OnSocketClosed() noexcept override; void OnSocketClosed() noexcept override;
}; };
#endif