httpd_client.c 17.1 KB
Newer Older
1
/*
Max Kellermann's avatar
Max Kellermann committed
2
 * Copyright (C) 2003-2011 The Music Player Daemon Project
3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
 * 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.
 */

20
#include "config.h"
21 22 23 24
#include "httpd_client.h"
#include "httpd_internal.h"
#include "fifo_buffer.h"
#include "page.h"
25
#include "icy_server.h"
26
#include "glib_compat.h"
27
#include "glib_socket.h"
28 29 30 31 32

#include <stdbool.h>
#include <assert.h>
#include <string.h>

33 34 35
#undef G_LOG_DOMAIN
#define G_LOG_DOMAIN "httpd_output"

36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94
struct httpd_client {
	/**
	 * The httpd output object this client is connected to.
	 */
	struct httpd_output *httpd;

	/**
	 * The TCP socket.
	 */
	GIOChannel *channel;

	/**
	 * The GLib main loop source id for reading from the socket,
	 * and to detect errors.
	 */
	guint read_source_id;

	/**
	 * The GLib main loop source id for writing to the socket.  If
	 * 0, then there is no event source currently (because there
	 * are no queued pages).
	 */
	guint write_source_id;

	/**
	 * For buffered reading.  This pointer is only valid while the
	 * HTTP request is read.
	 */
	struct fifo_buffer *input;

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

		/** reading the request headers */
		HEADERS,

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

	/**
	 * A queue of #page objects to be sent to the client.
	 */
	GQueue *pages;

	/**
	 * The #page which is currently being sent to the client.
	 */
	struct page *current_page;

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

96 97 98 99 100
        /**
         * If DLNA streaming was an option.
         */
        bool dlna_streaming_requested;

101 102
	/* ICY */

103 104 105 106 107 108
	/**
	 * Do we support sending Icy-Metadata to the client?  This is
	 * disabled if the httpd audio output uses encoder tags.
	 */
	bool metadata_supported;

109 110 111
	/**
	 * If we should sent icy metadata.
	 */
112
	bool metadata_requested;
113 114 115 116

	/**
	 * If the current metadata was already sent to the client.
	 */
117
	bool metadata_sent;
118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138

	/**
	 * The amount of streaming data between each metadata block
	 */
	guint metaint;

	/**
	 * The metadata as #page which is currently being sent to the client.
	 */
	struct page *metadata;

	/*
	 * 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.
	 */
	guint metadata_fill;
139 140 141 142 143 144 145 146 147 148 149 150 151
};

static void
httpd_client_unref_page(gpointer data, G_GNUC_UNUSED gpointer user_data)
{
	struct page *page = data;

	page_unref(page);
}

void
httpd_client_free(struct httpd_client *client)
{
152 153
	assert(client != NULL);

154 155 156 157 158 159 160 161 162 163 164 165
	if (client->state == RESPONSE) {
		if (client->write_source_id != 0)
			g_source_remove(client->write_source_id);

		if (client->current_page != NULL)
			page_unref(client->current_page);

		g_queue_foreach(client->pages, httpd_client_unref_page, NULL);
		g_queue_free(client->pages);
	} else
		fifo_buffer_free(client->input);

166 167 168
	if (client->metadata)
		page_unref (client->metadata);

169 170 171 172 173 174 175 176 177 178 179
	g_source_remove(client->read_source_id);
	g_io_channel_unref(client->channel);
	g_free(client);
}

/**
 * Frees the client and removes it from the server's client list.
 */
static void
httpd_client_close(struct httpd_client *client)
{
180 181
	assert(client != NULL);

182 183 184 185 186 187 188 189 190 191
	httpd_output_remove_client(client->httpd, client);
	httpd_client_free(client);
}

/**
 * Switch the client to the "RESPONSE" state.
 */
static void
httpd_client_begin_response(struct httpd_client *client)
{
192 193 194
	assert(client != NULL);
	assert(client->state != RESPONSE);

195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234
	client->state = RESPONSE;
	client->write_source_id = 0;
	client->pages = g_queue_new();
	client->current_page = NULL;

	httpd_output_send_header(client->httpd, client);
}

/**
 * Handle a line of the HTTP request.
 */
static bool
httpd_client_handle_line(struct httpd_client *client, const char *line)
{
	assert(client->state != RESPONSE);

	if (client->state == REQUEST) {
		if (strncmp(line, "GET /", 5) != 0) {
			/* only GET is supported */
			g_warning("malformed request line from client");
			return false;
		}

		line = strchr(line + 5, ' ');
		if (line == NULL || strncmp(line + 1, "HTTP/", 5) != 0) {
			/* HTTP/0.9 without request headers */
			httpd_client_begin_response(client);
			return true;
		}

		/* after the request line, request headers follow */
		client->state = HEADERS;
		return true;
	} else {
		if (*line == 0) {
			/* empty line: request is finished */
			httpd_client_begin_response(client);
			return true;
		}

235
		if (g_ascii_strncasecmp(line, "Icy-MetaData: 1", 15) == 0) {
236
			/* Send icy metadata */
237 238
			client->metadata_requested =
				client->metadata_supported;
239 240 241
			return true;
		}

242 243 244 245 246 247 248 249 250
		if (g_ascii_strncasecmp(line, "transferMode.dlna.org: Streaming", 32) == 0) {
			/* Send as dlna */
			client->dlna_streaming_requested = true;
			/* metadata is not supported by dlna streaming, so disable it */
			client->metadata_supported = false;
			client->metadata_requested = false;
			return true;
		}

251 252 253 254 255 256 257 258 259 260 261 262 263
		/* expect more request headers */
		return true;
	}
}

/**
 * Check if a complete line of input is present in the input buffer,
 * and duplicates it.  It is removed from the input buffer.  The
 * return value has to be freed with g_free().
 */
static char *
httpd_client_read_line(struct httpd_client *client)
{
264 265 266
	assert(client != NULL);
	assert(client->state != RESPONSE);

267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298
	const char *p, *newline;
	size_t length;
	char *line;

	p = fifo_buffer_read(client->input, &length);
	if (p == NULL)
		/* empty input buffer */
		return NULL;

	newline = memchr(p, '\n', length);
	if (newline == NULL)
		/* incomplete line */
		return NULL;

	line = g_strndup(p, newline - p);
	fifo_buffer_consume(client->input, newline - p + 1);

	/* remove trailing whitespace (e.g. '\r') */
	return g_strchomp(line);
}

/**
 * Sends the status line and response headers to the client.
 */
static bool
httpd_client_send_response(struct httpd_client *client)
{
	char buffer[1024];
	GError *error = NULL;
	GIOStatus status;
	gsize bytes_written;

299
	assert(client != NULL);
300 301
	assert(client->state == RESPONSE);

302
	if (client->dlna_streaming_requested) {
303
		g_snprintf(buffer, sizeof(buffer),
304
			   "HTTP/1.1 206 OK\r\n"
305
			   "Content-Type: %s\r\n"
306 307 308 309
			   "Content-Length: 10000\r\n"
			   "Content-RangeX: 0-1000000/1000000\r\n"
			   "transferMode.dlna.org: Streaming\r\n"
			   "Accept-Ranges: bytes\r\n"
310
			   "Connection: close\r\n"
311 312
			   "realTimeInfo.dlna.org: DLNA.ORG_TLAG=*\r\n"
			   "contentFeatures.dlna.org: DLNA.ORG_OP=01;DLNA.ORG_CI=0\r\n"
313 314
			   "\r\n",
			   client->httpd->content_type);
315 316

	} else if (client->metadata_requested) {
317 318
		gchar *metadata_header;

319 320 321 322 323 324
		metadata_header = icy_server_metadata_header(
			client->httpd->name,
			client->httpd->genre,
			client->httpd->website,
			client->httpd->content_type,
			client->metaint);
325 326 327 328

		g_strlcpy(buffer, metadata_header, sizeof(buffer));

		g_free(metadata_header);
329 330 331 332 333 334 335 336 337 338

       } else { /* revert to a normal HTTP request */
		g_snprintf(buffer, sizeof(buffer),
			   "HTTP/1.1 200 OK\r\n"
			   "Content-Type: %s\r\n"
			   "Connection: close\r\n"
			   "Pragma: no-cache\r\n"
			   "Cache-Control: no-cache, no-store\r\n"
			   "\r\n",
			   client->httpd->content_type);
339
	}
340 341 342 343

	status = g_io_channel_write_chars(client->channel,
					  buffer, strlen(buffer),
					  &bytes_written, &error);
344

345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377
	switch (status) {
	case G_IO_STATUS_NORMAL:
	case G_IO_STATUS_AGAIN:
		return true;

	case G_IO_STATUS_EOF:
		/* client has disconnected */

		httpd_client_close(client);
		return false;

	case G_IO_STATUS_ERROR:
		/* I/O error */

		g_warning("failed to write to client: %s", error->message);
		g_error_free(error);

		httpd_client_close(client);
		return false;
	}

	/* unreachable */
	httpd_client_close(client);
	return false;
}

/**
 * Data has been received from the client and it is appended to the
 * input buffer.
 */
static bool
httpd_client_received(struct httpd_client *client)
{
378 379 380
	assert(client != NULL);
	assert(client->state != RESPONSE);

381 382 383 384 385 386
	char *line;
	bool success;

	while ((line = httpd_client_read_line(client)) != NULL) {
		success = httpd_client_handle_line(client, line);
		g_free(line);
387 388
		if (!success) {
			assert(client->state != RESPONSE);
389
			return false;
390
		}
391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418

		if (client->state == RESPONSE) {
			if (!fifo_buffer_is_empty(client->input)) {
				g_warning("unexpected input from client");
				return false;
			}

			fifo_buffer_free(client->input);

			return httpd_client_send_response(client);
		}
	}

	return true;
}

static bool
httpd_client_read(struct httpd_client *client)
{
	char *p;
	size_t max_length;
	GError *error = NULL;
	GIOStatus status;
	gsize bytes_read;

	if (client->state == RESPONSE) {
		/* the client has already sent the request, and he
		   must not send more */
419 420 421 422 423 424 425 426
		char buffer[1];

		status = g_io_channel_read_chars(client->channel, buffer,
						 sizeof(buffer), &bytes_read,
						 NULL);
		if (status == G_IO_STATUS_NORMAL)
			g_warning("unexpected input from client");

427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485
		return false;
	}

	p = fifo_buffer_write(client->input, &max_length);
	if (p == NULL) {
		g_warning("buffer overflow");
		return false;
	}

	status = g_io_channel_read_chars(client->channel, p, max_length,
					 &bytes_read, &error);
	switch (status) {
	case G_IO_STATUS_NORMAL:
		fifo_buffer_append(client->input, bytes_read);
		return httpd_client_received(client);

	case G_IO_STATUS_AGAIN:
		/* try again later, after select() */
		return true;

	case G_IO_STATUS_EOF:
		/* peer disconnected */
		return false;

	case G_IO_STATUS_ERROR:
		/* I/O error */
		g_warning("failed to read from client: %s",
			  error->message);
		g_error_free(error);
		return false;
	}

	/* unreachable */
	return false;
}

static gboolean
httpd_client_in_event(G_GNUC_UNUSED GIOChannel *source, GIOCondition condition,
		      gpointer data)
{
	struct httpd_client *client = data;
	struct httpd_output *httpd = client->httpd;
	bool ret;

	g_mutex_lock(httpd->mutex);

	if (condition == G_IO_IN && httpd_client_read(client)) {
		ret = true;
	} else {
		httpd_client_close(client);
		ret = false;
	}

	g_mutex_unlock(httpd->mutex);

	return ret;
}

struct httpd_client *
486
httpd_client_new(struct httpd_output *httpd, int fd, bool metadata_supported)
487 488 489 490 491
{
	struct httpd_client *client = g_new(struct httpd_client, 1);

	client->httpd = httpd;

492
	client->channel = g_io_channel_new_socket(fd);
493 494 495 496 497 498 499 500 501 502 503 504 505 506 507

	/* GLib is responsible for closing the file descriptor */
	g_io_channel_set_close_on_unref(client->channel, true);
	/* NULL encoding means the stream is binary safe */
	g_io_channel_set_encoding(client->channel, NULL, NULL);
	/* we prefer to do buffering */
	g_io_channel_set_buffered(client->channel, false);

	client->read_source_id = g_io_add_watch(client->channel,
						G_IO_IN|G_IO_ERR|G_IO_HUP,
						httpd_client_in_event, client);

	client->input = fifo_buffer_new(4096);
	client->state = REQUEST;

508
	client->dlna_streaming_requested = false;
509
	client->metadata_supported = metadata_supported;
510 511
	client->metadata_requested = false;
	client->metadata_sent = true;
512 513 514 515 516
	client->metaint = 8192; /*TODO: just a std value */
	client->metadata = NULL;
	client->metadata_current_position = 0;
	client->metadata_fill = 0;

517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541
	return client;
}

static void
httpd_client_add_page_size(gpointer data, gpointer user_data)
{
	struct page *page = data;
	size_t *size = user_data;

	*size += page->size;
}

size_t
httpd_client_queue_size(const struct httpd_client *client)
{
	size_t size = 0;

	if (client->state != RESPONSE)
		return 0;

	g_queue_foreach(client->pages, httpd_client_add_page_size, &size);
	return size;
}

void
542
httpd_client_cancel(struct httpd_client *client)
543 544 545 546 547
{
	if (client->state != RESPONSE)
		return;

	g_queue_foreach(client->pages, httpd_client_unref_page, NULL);
548 549 550 551 552 553
	g_queue_clear(client->pages);

	if (client->write_source_id != 0 && client->current_page == NULL) {
		g_source_remove(client->write_source_id);
		client->write_source_id = 0;
	}
554 555 556 557 558 559 560 561 562 563 564 565 566 567 568 569 570
}

static GIOStatus
write_page_to_channel(GIOChannel *channel,
		      const struct page *page, size_t position,
		      gsize *bytes_written_r, GError **error)
{
	assert(channel != NULL);
	assert(page != NULL);
	assert(position < page->size);

	return g_io_channel_write_chars(channel,
					(const gchar*)page->data + position,
					page->size - position,
					bytes_written_r, error);
}

571 572 573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599 600 601 602 603 604 605 606
static GIOStatus
write_n_bytes_to_channel(GIOChannel *channel, const struct page *page,
			 size_t position, gint n,
			 gsize *bytes_written_r, GError **error)
{
	GIOStatus status;

	assert(channel != NULL);
	assert(page != NULL);
	assert(position < page->size);

	if (n == -1) {
		status =  write_page_to_channel (channel, page, position,
						 bytes_written_r, error);
	} else {
		status = g_io_channel_write_chars(channel,
						  (const gchar*)page->data + position,
						  n, bytes_written_r, error);
	}

	return status;
}

static gint
bytes_left_till_metadata (struct httpd_client *client)
{
	assert(client != NULL);

	if (client->metadata_requested &&
	    client->current_page->size - client->current_position
	    > client->metaint - client->metadata_fill)
		return client->metaint - client->metadata_fill;

	return -1;
}

607 608 609 610 611 612 613 614 615
static gboolean
httpd_client_out_event(GIOChannel *source,
		       G_GNUC_UNUSED GIOCondition condition, gpointer data)
{
	struct httpd_client *client = data;
	struct httpd_output *httpd = client->httpd;
	GError *error = NULL;
	GIOStatus status;
	gsize bytes_written;
616
	gint bytes_to_write;
617 618 619 620 621 622

	g_mutex_lock(httpd->mutex);

	assert(condition == G_IO_OUT);
	assert(client->state == RESPONSE);

623 624 625 626 627 628 629
	if (client->write_source_id == 0) {
		/* another thread has removed the event source while
		   this thread was waiting for httpd->mutex */
		g_mutex_unlock(httpd->mutex);
		return false;
	}

630 631 632 633 634
	if (client->current_page == NULL) {
		client->current_page = g_queue_pop_head(client->pages);
		client->current_position = 0;
	}

635 636 637 638 639 640 641 642 643 644 645 646 647 648 649 650 651 652 653
	bytes_to_write = bytes_left_till_metadata(client);

	if (bytes_to_write == 0) {
		gint metadata_to_write;

		metadata_to_write = client->metadata_current_position;

		if (!client->metadata_sent) {
			status = write_page_to_channel(source,
						       client->metadata,
						       metadata_to_write,
						       &bytes_written, &error);

			client->metadata_current_position += bytes_written;

			if (client->metadata->size
			    - client->metadata_current_position == 0) {
				client->metadata_fill = 0;
				client->metadata_current_position = 0;
654
				client->metadata_sent = true;
655 656 657 658 659 660 661 662 663 664 665 666 667 668 669 670 671 672 673 674 675 676 677 678 679 680 681 682
			}
		} else {
			struct page *empty_meta;
			guchar empty_data = 0;

			empty_meta = page_new_copy(&empty_data, 1);

			status = write_page_to_channel(source,
						       empty_meta,
						       metadata_to_write,
						       &bytes_written, &error);

			client->metadata_current_position += bytes_written;

			if (empty_meta->size
			    - client->metadata_current_position == 0) {
				client->metadata_fill = 0;
				client->metadata_current_position = 0;
			}
		}

		bytes_written = 0;
	} else {
		status = write_n_bytes_to_channel(source, client->current_page,
						  client->current_position, bytes_to_write,
						  &bytes_written, &error);
	}

683 684 685 686 687
	switch (status) {
	case G_IO_STATUS_NORMAL:
		client->current_position += bytes_written;
		assert(client->current_position <= client->current_page->size);

688 689 690
		if (client->metadata_requested)
			client->metadata_fill += bytes_written;

691 692 693 694 695 696 697 698 699 700 701 702 703 704 705 706 707 708 709 710 711 712 713 714 715 716 717 718 719 720 721 722 723 724 725 726 727 728 729 730 731 732 733 734 735 736 737 738 739 740 741 742 743 744 745 746 747 748 749 750
		if (client->current_position >= client->current_page->size) {
			page_unref(client->current_page);
			client->current_page = NULL;

			if (g_queue_is_empty(client->pages)) {
				/* all pages are sent: remove the
				   event source */
				client->write_source_id = 0;

				g_mutex_unlock(httpd->mutex);
				return false;
			}
		}

		g_mutex_unlock(httpd->mutex);
		return true;

	case G_IO_STATUS_AGAIN:
		g_mutex_unlock(httpd->mutex);
		return true;

	case G_IO_STATUS_EOF:
		/* client has disconnected */

		httpd_client_close(client);
		g_mutex_unlock(httpd->mutex);
		return false;

	case G_IO_STATUS_ERROR:
		/* I/O error */

		g_warning("failed to write to client: %s", error->message);
		g_error_free(error);

		httpd_client_close(client);
		g_mutex_unlock(httpd->mutex);
		return false;
	}

	/* unreachable */
	httpd_client_close(client);
	g_mutex_unlock(httpd->mutex);
	return false;
}

void
httpd_client_send(struct httpd_client *client, struct page *page)
{
	if (client->state != RESPONSE)
		/* the client is still writing the HTTP request */
		return;

	page_ref(page);
	g_queue_push_tail(client->pages, page);

	if (client->write_source_id == 0)
		client->write_source_id =
			g_io_add_watch(client->channel, G_IO_OUT,
				       httpd_client_out_event, client);
}
751 752 753 754 755 756 757 758 759 760 761 762 763

void
httpd_client_send_metadata(struct httpd_client *client, struct page *page)
{
	if (client->metadata) {
		page_unref(client->metadata);
		client->metadata = NULL;
	}

	g_return_if_fail (page);

	page_ref(page);
	client->metadata = page;
764
	client->metadata_sent = false;
765
}