HttpdClient.hxx 4.13 KB
Newer Older
1
/*
Max Kellermann's avatar
Max Kellermann committed
2
 * Copyright 2003-2017 The Music Player Daemon Project
3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22
 * 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

23
#include "event/BufferedSocket.hxx"
24
#include "Compiler.h"
25

26 27
#include <boost/intrusive/link_mode.hpp>
#include <boost/intrusive/list_hook.hpp>
28

29
#include <queue>
30 31 32 33
#include <list>

#include <stddef.h>

34
class HttpdOutput;
Max Kellermann's avatar
Max Kellermann committed
35
class Page;
36

37 38 39
class HttpdClient final
	: BufferedSocket,
	  public boost::intrusive::list_base_hook<boost::intrusive::link_mode<boost::intrusive::normal_link>> {
40 41 42
	/**
	 * The httpd output object this client is connected to.
	 */
43
	HttpdOutput &httpd;
44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59

	/**
	 * The current state of the client.
	 */
	enum {
		/** reading the request line */
		REQUEST,

		/** reading the request headers */
		HEADERS,

		/** sending the HTTP response */
		RESPONSE,
	} state;

	/**
Max Kellermann's avatar
Max Kellermann committed
60
	 * A queue of #Page objects to be sent to the client.
61
	 */
62
	std::queue<Page *, std::list<Page *>> pages;
63

64 65 66 67 68
	/**
	 * The sum of all page sizes in #pages.
	 */
	size_t queue_size;

69 70 71
	/**
	 * The #page which is currently being sent to the client.
	 */
Max Kellermann's avatar
Max Kellermann committed
72
	Page *current_page;
73 74 75 76 77 78 79

	/**
	 * The amount of bytes which were already sent from
	 * #current_page.
	 */
	size_t current_position;

80 81 82 83 84
	/**
	 * Is this a HEAD request?
	 */
	bool head_method;

85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110
	/**
         * If DLNA streaming was an option.
         */
	bool dlna_streaming_requested;

	/* 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;

	/**
	 * If the current metadata was already sent to the client.
	 */
	bool metadata_sent;

	/**
	 * The amount of streaming data between each metadata block
	 */
111
	unsigned metaint;
112 113

	/**
Max Kellermann's avatar
Max Kellermann committed
114
	 * The metadata as #Page which is currently being sent to the client.
115
	 */
Max Kellermann's avatar
Max Kellermann committed
116
	Page *metadata;
117 118 119 120 121 122 123 124 125 126

	/*
	 * The amount of bytes which were already sent from the metadata.
	 */
	size_t metadata_current_position;

	/**
	 * The amount of streaming data sent to the client
	 * since the last icy information was sent.
	 */
127
	unsigned metadata_fill;
128 129 130 131

public:
	/**
	 * @param httpd the HTTP output device
Max Kellermann's avatar
Max Kellermann committed
132
	 * @param _fd the socket file descriptor
133
	 */
134
	HttpdClient(HttpdOutput &httpd, int _fd, EventLoop &_loop,
135
		    bool _metadata_supported);
136 137 138

	/**
	 * Note: this does not remove the client from the
139
	 * #HttpdOutput object.
140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170
	 */
	~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 the "RESPONSE" state.
	 */
	void BeginResponse();

	/**
	 * Sends the status line and response headers to the client.
	 */
	bool SendResponse();

	gcc_pure
171
	ssize_t GetBytesTillMetaData() const noexcept;
172

173 174 175 176
	ssize_t TryWritePage(const Page &page, size_t position);
	ssize_t TryWritePageN(const Page &page, size_t position, ssize_t n);

	bool TryWrite();
177 178 179 180

	/**
	 * Appends a page to the client's queue.
	 */
Max Kellermann's avatar
Max Kellermann committed
181
	void PushPage(Page *page);
182 183 184 185

	/**
	 * Sends the passed metadata.
	 */
186 187
	void PushMetaData(Page *page);

188 189 190
private:
	void ClearQueue();

191 192
protected:
	virtual bool OnSocketReady(unsigned flags) override;
193
	virtual InputResult OnSocketInput(void *data, size_t length) override;
194
	void OnSocketError(std::exception_ptr ep) override;
195
	virtual void OnSocketClosed() override;
196 197 198
};

#endif