/* * Copyright 2003-2017 The Music Player Daemon Project * http://www.musicpd.org * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License along * with this program; if not, write to the Free Software Foundation, Inc., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ #ifndef MPD_OUTPUT_HTTPD_CLIENT_HXX #define MPD_OUTPUT_HTTPD_CLIENT_HXX #include "Page.hxx" #include "event/BufferedSocket.hxx" #include "Compiler.h" #include <boost/intrusive/link_mode.hpp> #include <boost/intrusive/list_hook.hpp> #include <queue> #include <list> #include <stddef.h> class UniqueSocketDescriptor; class HttpdOutput; class HttpdClient final : BufferedSocket, public boost::intrusive::list_base_hook<boost::intrusive::link_mode<boost::intrusive::normal_link>> { /** * The httpd output object this client is connected to. */ HttpdOutput &httpd; /** * The current state of the client. */ enum class State { /** reading the request line */ REQUEST, /** reading the request headers */ HEADERS, /** sending the HTTP response */ RESPONSE, } state = State::REQUEST; /** * A queue of #Page objects to be sent to the client. */ std::queue<PagePtr, std::list<PagePtr>> pages; /** * The sum of all page sizes in #pages. */ size_t queue_size = 0; /** * The #page which is currently being sent to the client. */ PagePtr current_page; /** * The amount of bytes which were already sent from * #current_page. */ size_t current_position; /** * Is this a HEAD request? */ bool head_method = false; /* ICY */ /** * Do we support sending Icy-Metadata to the client? This is * disabled if the httpd audio output uses encoder tags. */ bool metadata_supported; /** * If we should sent icy metadata. */ bool metadata_requested = false; /** * If the current metadata was already sent to the client. */ bool metadata_sent = false; /** * The amount of streaming data between each metadata block */ unsigned metaint = 8192; /*TODO: just a std value */ /** * The metadata as #Page which is currently being sent to the client. */ PagePtr metadata; /* * The amount of bytes which were already sent from the metadata. */ size_t metadata_current_position = 0; /** * The amount of streaming data sent to the client * since the last icy information was sent. */ unsigned metadata_fill = 0; public: /** * @param httpd the HTTP output device * @param _fd the socket file descriptor */ HttpdClient(HttpdOutput &httpd, UniqueSocketDescriptor _fd, EventLoop &_loop, bool _metadata_supported); /** * Note: this does not remove the client from the * #HttpdOutput object. */ ~HttpdClient(); /** * Frees the client and removes it from the server's client list. */ void Close(); void LockClose(); /** * Clears the page queue. */ void CancelQueue(); /** * Handle a line of the HTTP request. */ bool HandleLine(const char *line); /** * Switch the client to #State::RESPONSE. */ void BeginResponse(); /** * Sends the status line and response headers to the client. */ bool SendResponse(); gcc_pure ssize_t GetBytesTillMetaData() const noexcept; ssize_t TryWritePage(const Page &page, size_t position); ssize_t TryWritePageN(const Page &page, size_t position, ssize_t n); bool TryWrite(); /** * Appends a page to the client's queue. */ void PushPage(PagePtr page); /** * Sends the passed metadata. */ void PushMetaData(PagePtr page); private: void ClearQueue(); protected: /* virtual methods from class SocketMonitor */ bool OnSocketReady(unsigned flags) noexcept override; InputResult OnSocketInput(void *data, size_t length) noexcept override; void OnSocketError(std::exception_ptr ep) noexcept override; void OnSocketClosed() noexcept override; }; #endif