inputStream_http.c 25.9 KB
Newer Older
Warren Dukes's avatar
Warren Dukes committed
1
/* the Music Player Daemon (MPD)
2
 * Copyright (C) 2003-2007 by Warren Dukes (warren.dukes@gmail.com)
Warren Dukes's avatar
Warren Dukes committed
3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
 * This project's homepage is: 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., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 */

#include "inputStream_http.h"
20
#include "inputStream_http_auth.h"
Warren Dukes's avatar
Warren Dukes committed
21 22

#include "utils.h"
Warren Dukes's avatar
Warren Dukes committed
23
#include "log.h"
24
#include "conf.h"
25
#include "os_compat.h"
26
#include "ringbuf.h"
27
#include "condition.h"
28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51

enum conn_state { /* only written by io thread, read by both */
	CONN_STATE_NEW,             /* just (re)initialized */
	CONN_STATE_REDIRECT,        /* redirect */
	CONN_STATE_CONNECTED,       /* connected to the socket */
	CONN_STATE_REQUESTED,       /* sent HTTP request */
	CONN_STATE_RESP_HEAD,       /* reading HTTP response header */
	CONN_STATE_PREBUFFER,       /* prebuffering data stream */
	CONN_STATE_BUFFER,          /* buffering data stream */
	CONN_STATE_BUFFER_FULL,     /* reading actual data stream */
	CONN_STATE_CLOSED           /* it's over, time to die */
};

/* used by all HTTP header matching */
#define match(s) !strncasecmp(cur, s, (offset = sizeof(s) - 1))

#define assert_state(st) assert(data->state == st)
#define assert_state2(s1,s2) assert((data->state == s1) || (data->state == s2))

enum conn_action { /* only written by control thread, read by both */
	CONN_ACTION_NONE,
	CONN_ACTION_CLOSE,
	CONN_ACTION_DOSEEK
};
Warren Dukes's avatar
Warren Dukes committed
52

53 54
#define HTTP_BUFFER_SIZE_DEFAULT        131072
#define HTTP_PREBUFFER_SIZE_DEFAULT	(HTTP_BUFFER_SIZE_DEFAULT >> 2)
Warren Dukes's avatar
Warren Dukes committed
55 56
#define HTTP_REDIRECT_MAX    10

57 58 59 60 61 62
static char *proxy_host;
static char *proxy_port;
static char *proxy_user;
static char *proxy_password;
static size_t buffer_size = HTTP_BUFFER_SIZE_DEFAULT;
static size_t prebuffer_size = HTTP_PREBUFFER_SIZE_DEFAULT;
63

64 65 66
struct http_data {
	int fd;
	enum conn_state state;
67

68 69 70
	/* { we may have a non-multithreaded HTTP discipline in the future */
		enum conn_action action;
		int pipe_fds[2];
71

72 73
		pthread_t io_thread;
		struct ringbuf *rb;
74

75 76 77
		struct condition full_cond;
		struct condition empty_cond;
		struct condition action_cond;
78
	/* } */
79

80 81 82 83 84 85 86 87 88
	int nr_redirect;
	size_t icy_metaint;
	size_t icy_offset;
	char *host;
	char *path;
	char *port;
	char *proxy_auth;
	char *http_auth;
};
89

90
static int awaken_buffer_task(struct http_data *data);
91

92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110
static void init_http_data(struct http_data *data)
{
	data->fd = -1;
	data->action = CONN_ACTION_NONE;
	data->state = CONN_STATE_NEW;
	init_async_pipe(data->pipe_fds);

	data->proxy_auth = proxy_host ?
	                   proxy_auth_string(proxy_user, proxy_password) :
	                   NULL;
	data->http_auth = NULL;
	data->host = NULL;
	data->path = NULL;
	data->port = NULL;
	data->nr_redirect = 0;
	data->icy_metaint = 0;
	data->icy_offset = 0;
	data->rb = ringbuf_create(buffer_size);

111 112 113
	cond_init(&data->action_cond);
	cond_init(&data->full_cond);
	cond_init(&data->empty_cond);
114 115
}

116
static struct http_data *new_http_data(void)
Avuton Olrich's avatar
Avuton Olrich committed
117
{
118 119
	struct http_data *ret = xmalloc(sizeof(struct http_data));
	init_http_data(ret);
Avuton Olrich's avatar
Avuton Olrich committed
120
	return ret;
Warren Dukes's avatar
Warren Dukes committed
121 122
}

123
static void free_http_data(struct http_data * data)
Avuton Olrich's avatar
Avuton Olrich committed
124
{
125 126 127 128 129 130
	if (data->host) free(data->host);
	if (data->path) free(data->path);
	if (data->port) free(data->port);
	if (data->proxy_auth) free(data->proxy_auth);
	if (data->http_auth) free(data->http_auth);

131 132 133
	cond_destroy(&data->action_cond);
	cond_destroy(&data->full_cond);
	cond_destroy(&data->empty_cond);
134 135 136 137

	xclose(data->pipe_fds[0]);
	xclose(data->pipe_fds[1]);
	ringbuf_free(data->rb);
Avuton Olrich's avatar
Avuton Olrich committed
138
	free(data);
Warren Dukes's avatar
Warren Dukes committed
139 140
}

141
static int parse_url(struct http_data * data, char *url)
Avuton Olrich's avatar
Avuton Olrich committed
142 143 144 145 146
{
	char *colon;
	char *slash;
	char *at;
	int len;
147 148
	char *cur = url;
	size_t offset;
Warren Dukes's avatar
Warren Dukes committed
149

150
	if (!match("http://"))
Avuton Olrich's avatar
Avuton Olrich committed
151
		return -1;
Warren Dukes's avatar
Warren Dukes committed
152

153 154 155
	cur = url + offset;
	colon = strchr(cur, ':');
	at = strchr(cur, '@');
Warren Dukes's avatar
Warren Dukes committed
156

157 158 159
	if (data->http_auth) {
		free(data->http_auth);
		data->http_auth = NULL;
160 161
	}

Avuton Olrich's avatar
Avuton Olrich committed
162 163 164
	if (at) {
		char *user;
		char *passwd;
165

Avuton Olrich's avatar
Avuton Olrich committed
166
		if (colon && colon < at) {
167 168 169
			user = xmalloc(colon - cur + 1);
			memcpy(user, cur, colon - cur);
			user[colon - cur] = '\0';
Avuton Olrich's avatar
Avuton Olrich committed
170

171
			passwd = xmalloc(at - colon);
Eric Wong's avatar
Eric Wong committed
172
			memcpy(passwd, colon + 1, at - colon - 1);
Avuton Olrich's avatar
Avuton Olrich committed
173 174
			passwd[at - colon - 1] = '\0';
		} else {
175 176 177
			user = xmalloc(at - cur + 1);
			memcpy(user, cur, at - cur);
			user[at - cur] = '\0';
178

179
			passwd = xstrdup("");
180 181
		}

182
		data->http_auth = http_auth_string(user, passwd);
183 184 185 186

		free(user);
		free(passwd);

187 188
		cur = at + 1;
		colon = strchr(cur, ':');
189 190
	}

191
	slash = strchr(cur, '/');
Warren Dukes's avatar
Warren Dukes committed
192

Avuton Olrich's avatar
Avuton Olrich committed
193 194
	if (slash && colon && slash <= colon)
		return -1;
Warren Dukes's avatar
Warren Dukes committed
195

Avuton Olrich's avatar
Avuton Olrich committed
196 197
	/* fetch the host portion */
	if (colon)
198
		len = colon - cur + 1;
Avuton Olrich's avatar
Avuton Olrich committed
199
	else if (slash)
200
		len = slash - cur + 1;
Avuton Olrich's avatar
Avuton Olrich committed
201
	else
202
		len = strlen(cur) + 1;
Warren Dukes's avatar
Warren Dukes committed
203

Avuton Olrich's avatar
Avuton Olrich committed
204 205
	if (len <= 1)
		return -1;
Warren Dukes's avatar
Warren Dukes committed
206

207 208
	if (data->host)
		free(data->host);
209
	data->host = xmalloc(len);
210
	memcpy(data->host, cur, len - 1);
Avuton Olrich's avatar
Avuton Olrich committed
211
	data->host[len - 1] = '\0';
212 213
	if (data->port)
		free(data->port);
Avuton Olrich's avatar
Avuton Olrich committed
214 215 216 217 218
	/* fetch the port */
	if (colon && (!slash || slash != colon + 1)) {
		len = strlen(colon) - 1;
		if (slash)
			len -= strlen(slash);
219
		data->port = xmalloc(len + 1);
Eric Wong's avatar
Eric Wong committed
220
		memcpy(data->port, colon + 1, len);
Avuton Olrich's avatar
Avuton Olrich committed
221
		data->port[len] = '\0';
222
		DEBUG(__FILE__ ": Port: %s\n", data->port);
Avuton Olrich's avatar
Avuton Olrich committed
223
	} else {
224
		data->port = xstrdup("80");
225
	}
Warren Dukes's avatar
Warren Dukes committed
226

227 228
	if (data->path)
		free(data->path);
Avuton Olrich's avatar
Avuton Olrich committed
229
	/* fetch the path */
230
	data->path = proxy_host ? xstrdup(url) : xstrdup(slash ? slash : "/");
Avuton Olrich's avatar
Avuton Olrich committed
231 232

	return 0;
Warren Dukes's avatar
Warren Dukes committed
233 234
}

235 236 237 238 239 240 241 242
/* triggers an action and waits for completion */
static int trigger_action(struct http_data *data,
                          enum conn_action action,
                          int nonblocking)
{
	int ret = -1;

	assert(!pthread_equal(data->io_thread, pthread_self()));
243
	cond_enter(&data->action_cond);
244 245 246 247 248 249 250 251 252 253
	if (data->action != CONN_ACTION_NONE)
		goto out;
	data->action = action;
	if (awaken_buffer_task(data)) {
		/* DEBUG("wokeup from cond_wait to trigger action\n"); */
	} else if (xwrite(data->pipe_fds[1], "", 1) != 1) {
		ERROR(__FILE__ ": pipe full, couldn't trigger action\n");
		data->action = CONN_ACTION_NONE;
		goto out;
	}
254 255 256 257
	if (nonblocking)
		cond_timedwait(&data->action_cond, 1);
	else
		cond_wait(&data->action_cond);
258 259
	ret = 0;
out:
260
	cond_leave(&data->action_cond);
261 262 263 264 265 266 267
	return ret;
}

static int take_action(struct http_data *data)
{
	assert(pthread_equal(data->io_thread, pthread_self()));

268
	cond_enter(&data->action_cond);
269 270
	switch (data->action) {
	case CONN_ACTION_NONE:
271
		cond_leave(&data->action_cond);
272 273 274 275 276 277 278 279 280 281
		return 0;
	case CONN_ACTION_DOSEEK:
		data->state = CONN_STATE_NEW;
		break;
	case CONN_ACTION_CLOSE:
		data->state = CONN_STATE_CLOSED;
	}
	xclose(data->fd);
	data->fd = -1;
	data->action = CONN_ACTION_NONE;
282 283
	cond_signal_sync(&data->action_cond);
	cond_leave(&data->action_cond);
284 285 286 287 288 289 290 291 292 293 294
	return 1;
}

static int err_close(struct http_data *data)
{
	assert(pthread_equal(data->io_thread, pthread_self()));
	xclose(data->fd);
	data->state = CONN_STATE_CLOSED;
	return -1;
}

295 296 297
/* returns -1 on error, 0 on success (and sets dest) */
static int my_getaddrinfo(struct addrinfo **dest,
                          const char *host, const char *port)
Avuton Olrich's avatar
Avuton Olrich committed
298
{
299
	struct addrinfo hints;
Eric Wong's avatar
Eric Wong committed
300
	int error;
301

Avuton Olrich's avatar
Avuton Olrich committed
302 303 304 305 306 307 308 309 310
	hints.ai_flags = 0;
	hints.ai_family = PF_UNSPEC;
	hints.ai_socktype = SOCK_STREAM;
	hints.ai_protocol = IPPROTO_TCP;
	hints.ai_addrlen = 0;
	hints.ai_addr = NULL;
	hints.ai_canonname = NULL;
	hints.ai_next = NULL;

311 312 313
	if ((error = getaddrinfo(host, port, &hints, dest))) {
		DEBUG(__FILE__ ": Error getting address info for %s:%s: %s\n",
		      host, port, gai_strerror(error));
314 315
		return -1;
	}
316 317 318 319 320 321 322 323
	return 0;
}

/* returns the fd we connected to, or -1 on error */
static int my_connect_addrs(struct addrinfo *ans)
{
	int fd;
	struct addrinfo *ap;
Avuton Olrich's avatar
Avuton Olrich committed
324

325
	/* loop through possible addresses */
Avuton Olrich's avatar
Avuton Olrich committed
326
	for (ap = ans; ap != NULL; ap = ap->ai_next) {
327 328 329
		fd = socket(ap->ai_family, ap->ai_socktype, ap->ai_protocol);
		if (fd < 0) {
			DEBUG(__FILE__ ": unable to get socket: %s\n",
Avuton Olrich's avatar
Avuton Olrich committed
330
			      strerror(errno));
331
			continue;
332
		}
Avuton Olrich's avatar
Avuton Olrich committed
333

334 335 336 337
		set_nonblocking(fd);
		if (connect(fd, ap->ai_addr, ap->ai_addrlen) >= 0
		    || errno == EINPROGRESS)
			return fd;	/* success */
338
		DEBUG(__FILE__ ": unable to connect: %s\n", strerror(errno));
339
		xclose(fd); /* failed, get the next one */
Avuton Olrich's avatar
Avuton Olrich committed
340
	}
341 342
	return -1;
}
Warren Dukes's avatar
Warren Dukes committed
343

344
static int init_connection(struct http_data *data)
345 346 347
{
	struct addrinfo *ans = NULL;

348 349 350 351 352
	assert(pthread_equal(data->io_thread, pthread_self()));
	assert_state2(CONN_STATE_NEW, CONN_STATE_REDIRECT);

	if ((proxy_host ? my_getaddrinfo(&ans, proxy_host, proxy_port) :
	                  my_getaddrinfo(&ans, data->host, data->port)) < 0)
353 354
		return -1;

355 356
	assert(data->fd < 0);
	data->fd = my_connect_addrs(ans);
357
	freeaddrinfo(ans);
358

359
	if (data->fd < 0)
360
		return -1; /* failed */
361
	data->state = CONN_STATE_CONNECTED;
362
	return 0;
Warren Dukes's avatar
Warren Dukes committed
363 364
}

365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382
#define my_nfds(d) ((d->fd > d->pipe_fds[0] ? d->fd : d->pipe_fds[0]) + 1)

static int pipe_notified(struct http_data * data, fd_set *rfds)
{
	char buf;
	int fd = data->pipe_fds[0];

	assert(pthread_equal(data->io_thread, pthread_self()));
	return FD_ISSET(fd, rfds) && (xread(fd, &buf, 1) == 1);
}

enum await_result {
	AWAIT_READY,
	AWAIT_ACTION_PENDING,
	AWAIT_ERROR
};

static enum await_result socket_error_or_ready(int fd)
Avuton Olrich's avatar
Avuton Olrich committed
383 384
{
	int ret;
385 386
	int error = 0;
	socklen_t error_len = sizeof(int);
Avuton Olrich's avatar
Avuton Olrich committed
387

388 389 390
	ret = getsockopt(fd, SOL_SOCKET, SO_ERROR, &error, &error_len);
	return (ret < 0 || error) ? AWAIT_ERROR : AWAIT_READY;
}
Avuton Olrich's avatar
Avuton Olrich committed
391

392 393 394
static enum await_result await_sendable(struct http_data *data)
{
	fd_set rfds, wfds;
Avuton Olrich's avatar
Avuton Olrich committed
395

396 397
	assert(pthread_equal(data->io_thread, pthread_self()));
	assert_state(CONN_STATE_CONNECTED);
Avuton Olrich's avatar
Avuton Olrich committed
398

399 400 401 402 403 404 405 406 407 408
	FD_ZERO(&rfds);
	FD_ZERO(&wfds);
	FD_SET(data->pipe_fds[0], &rfds);
	FD_SET(data->fd, &wfds);

	if (select(my_nfds(data), &rfds, &wfds, NULL, NULL) <= 0)
		return AWAIT_ERROR;
	if (pipe_notified(data, &rfds)) return AWAIT_ACTION_PENDING;
	return socket_error_or_ready(data->fd);
}
Avuton Olrich's avatar
Avuton Olrich committed
409

410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429
static enum await_result await_recvable(struct http_data *data)
{
	fd_set rfds;

	assert(pthread_equal(data->io_thread, pthread_self()));

	FD_ZERO(&rfds);
	FD_SET(data->pipe_fds[0], &rfds);
	FD_SET(data->fd, &rfds);

	if (select(my_nfds(data), &rfds, NULL, NULL, NULL) <= 0)
		return AWAIT_ERROR;
	if (pipe_notified(data, &rfds)) return AWAIT_ACTION_PENDING;
	return socket_error_or_ready(data->fd);
}

static void await_buffer_space(struct http_data *data)
{
	assert(pthread_equal(data->io_thread, pthread_self()));
	assert_state(CONN_STATE_BUFFER_FULL);
430
	cond_wait(&data->full_cond);
431 432 433 434 435 436 437 438
	if (ringbuf_write_space(data->rb) > 0)
		data->state = CONN_STATE_BUFFER;
	/* else spurious wakeup or action triggered ... */
}

static void feed_starved(struct http_data *data)
{
	assert(pthread_equal(data->io_thread, pthread_self()));
439
	cond_signal_async(&data->empty_cond);
440 441 442 443 444
}

static int starved_wait(struct http_data *data, const long sec)
{
	assert(!pthread_equal(data->io_thread, pthread_self()));
445
	return cond_timedwait(&data->empty_cond, sec);
446 447 448 449 450
}

static int awaken_buffer_task(struct http_data *data)
{
	assert(!pthread_equal(data->io_thread, pthread_self()));
451 452

	return ! cond_signal_async(&data->full_cond);
453 454 455 456 457 458 459 460 461 462 463 464 465 466
}

static ssize_t buffer_data(InputStream *is)
{
	struct iovec vec[2];
	ssize_t r;
	struct http_data *data = (struct http_data *)is->data;

	assert(pthread_equal(data->io_thread, pthread_self()));
	assert_state2(CONN_STATE_BUFFER, CONN_STATE_PREBUFFER);

	if (!ringbuf_get_write_vector(data->rb, vec)) {
		data->state = CONN_STATE_BUFFER_FULL;
		return 0;
Avuton Olrich's avatar
Avuton Olrich committed
467
	}
468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488
	r = readv(data->fd, vec, vec[1].iov_len ? 2 : 1);
	if (r > 0) {
		size_t buflen;

		ringbuf_write_advance(data->rb, r);
		buflen = ringbuf_read_space(data->rb);
		if (buflen == 0 || buflen < data->icy_metaint)
			data->state = CONN_STATE_PREBUFFER;
		else if (buflen >= prebuffer_size)
			data->state = CONN_STATE_BUFFER;
		if (data->state == CONN_STATE_BUFFER)
			feed_starved(data);
		return r;
	} else if (r < 0) {
		if (errno == EAGAIN || errno == EINTR)
			return 0;
		is->error = errno;
	}
	err_close(data);
	return r;
}
Avuton Olrich's avatar
Avuton Olrich committed
489

490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506
/*
 * This requires the socket to be writable beforehand (determined via
 * select(2)).  This does NOT retry or continue if we can't write the
 * HTTP header in one shot.  One reason for this is laziness, I don't
 * want to have to store the header when recalling this function, but
 * the other reason is practical, too: if we can't send a small HTTP
 * request without blocking, the connection is pathetic anyways and we
 * should just stop
 *
 * Returns -1 on error, 0 on success
 */
static int send_request(InputStream * is)
{
	struct http_data *data = (struct http_data *) is->data;
	int length;
	ssize_t nbytes;
	char request[2048]; /* todo(?): write item-at-a-time and cork */
Avuton Olrich's avatar
Avuton Olrich committed
507

508 509 510
	assert(pthread_equal(data->io_thread, pthread_self()));
	assert_state(CONN_STATE_CONNECTED);
	length = snprintf(request, sizeof(request),
511 512
	                 "GET %s HTTP/1.1\r\n"
	                 "Host: %s\r\n"
513
	                 "Connection: close\r\n"
514
	                 "User-Agent: " PACKAGE_NAME "/" PACKAGE_VERSION "\r\n"
515 516 517 518 519 520
	                 "Range: bytes=%ld-\r\n"
	                 "%s"  /* authorization */
	                 "Icy-Metadata:1\r\n"
	                 "\r\n",
	                 data->path,
	                 data->host,
521 522 523 524 525 526 527 528 529
	                 is->offset,
	                 data->proxy_auth ? data->proxy_auth :
	                  (data->http_auth ? data->http_auth : ""));
	if (length < 0 || length >= (int)sizeof(request))
		return err_close(data);
	nbytes = write(data->fd, request, (size_t)length);
	if (nbytes < 0 || nbytes != (ssize_t)length)
		return err_close(data);
	data->state = CONN_STATE_REQUESTED;
Avuton Olrich's avatar
Avuton Olrich committed
530
	return 0;
Warren Dukes's avatar
Warren Dukes committed
531 532
}

533 534
/* handles parsing of the first line of the HTTP response */
static int parse_response_code(InputStream * is, const char *response)
Avuton Olrich's avatar
Avuton Olrich committed
535
{
536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552
	size_t offset;
	const char *cur = response;

	is->seekable = 0;
	if (match("HTTP/1.0 ")) {
		return atoi(cur + offset);
	} else if (match("HTTP/1.1 ")) {
		is->seekable = 1;
		return atoi(cur + offset);
	} else if (match("ICY 200 OK")) {
		return 200;
	} else if (match("ICY 400 Server Full")) {
		return 400;
	} else if (match("ICY 404"))
		return 404;
	return 0;
}
Avuton Olrich's avatar
Avuton Olrich committed
553

554 555 556 557
static int leading_space(int c)
{
	return (c == ' ' || c == '\t');
}
Avuton Olrich's avatar
Avuton Olrich committed
558

559 560 561 562
static int parse_header_dup(char **dst, char *cur)
{
	char *eol;
	size_t len;
Avuton Olrich's avatar
Avuton Olrich committed
563

564 565 566 567 568 569 570 571 572 573 574
	if (!(eol = strstr(cur, "\r\n")))
		return -1;
	*eol = '\0';
	while (leading_space(*cur))
		cur++;
	len = strlen(cur) + 1;
	*dst = xrealloc(*dst, len);
	memcpy(*dst, cur, len);
	*eol = '\r';
	return 0;
}
Avuton Olrich's avatar
Avuton Olrich committed
575

576 577 578 579 580 581 582
static int parse_redirect(InputStream * is, char *response, const char *needle)
{
	char *url = NULL;
	char *cur = strstr(response, "\r\n");
	size_t offset;
	struct http_data *data = (struct http_data *) is->data;
	int ret;
Avuton Olrich's avatar
Avuton Olrich committed
583

584 585 586 587 588
	while (cur && cur != needle) {
		assert(cur < needle);
		if (match("\r\nLocation:"))
			goto found;
		cur = strstr(cur + 2, "\r\n");
Avuton Olrich's avatar
Avuton Olrich committed
589
	}
590 591 592
	return -1;
found:
	if (parse_header_dup(&url, cur + offset) < 0)
Avuton Olrich's avatar
Avuton Olrich committed
593
		return -1;
594 595 596 597 598 599 600
	ret = parse_url(data, url);
	free(url);
	if (!ret && data->nr_redirect < HTTP_REDIRECT_MAX) {
		data->nr_redirect++;
		xclose(data->fd);
		data->fd = -1;
		data->state = CONN_STATE_REDIRECT;
Max Kellermann's avatar
Max Kellermann committed
601
		is->ready = 1;
602
		return 0; /* success */
Avuton Olrich's avatar
Avuton Olrich committed
603
	}
604 605
	return -1;
}
Avuton Olrich's avatar
Avuton Olrich committed
606

607 608 609 610 611 612 613 614 615 616 617 618
static int parse_headers(InputStream * is, char *response, const char *needle)
{
	struct http_data *data = (struct http_data *) is->data;
	char *cur = strstr(response, "\r\n");
	size_t offset;
	long tmp;

	data->icy_metaint = 0;
	data->icy_offset = 0;
	if (is->mime) {
		free(is->mime);
		is->mime = NULL;
Avuton Olrich's avatar
Avuton Olrich committed
619
	}
620 621 622 623 624
	if (is->metaName) {
		free(is->metaName);
		is->metaName = NULL;
	}
	is->size = 0;
Avuton Olrich's avatar
Avuton Olrich committed
625

626 627 628 629 630 631 632 633 634 635 636 637 638 639 640 641 642 643 644 645 646 647
	while (cur && cur != needle) {
		assert(cur < needle);
		if (match("\r\nContent-Length:")) {
			if ((tmp = atol(cur + offset)) >= 0)
				is->size = tmp;
		} else if (match("\r\nicy-metaint:")) {
			if ((tmp = atol(cur + offset)) >= 0)
				data->icy_metaint = tmp;
		} else if (match("\r\nicy-name:") ||
		           match("\r\nice-name:") ||
		           match("\r\nx-audiocast-name:")) {
			if (parse_header_dup(&is->metaName, cur + offset) < 0)
				return -1;
			DEBUG(__FILE__": metaName: %s\n", is->metaName);
		} else if (match("\r\nContent-Type:")) {
			if (parse_header_dup(&is->mime, cur + offset) < 0)
				return -1;
		}
		cur = strstr(cur + 2, "\r\n");
	}
	return 0;
}
Avuton Olrich's avatar
Avuton Olrich committed
648

649 650 651 652 653 654 655 656 657 658 659 660 661 662 663 664 665 666 667 668 669 670 671
/* Returns -1 on error, 0 on success */
static int recv_response(InputStream * is)
{
	struct http_data *data = (struct http_data *) is->data;
	char *needle;
	char response[2048];
	const size_t response_max = sizeof(response) - 1;
	ssize_t r;
	ssize_t peeked;

	assert(pthread_equal(data->io_thread, pthread_self()));
	assert_state2(CONN_STATE_RESP_HEAD, CONN_STATE_REQUESTED);
	do {
		r = recv(data->fd, response, response_max, MSG_PEEK);
	} while (r < 0 && errno == EINTR);
	if (r <= 0)
		return err_close(data); /* EOF */
	response[r] = '\0';
	if (!(needle = strstr(response, "\r\n\r\n"))) {
		if ((size_t)r == response_max)
			return err_close(data);
		/* response too small, try again */
		data->state = CONN_STATE_RESP_HEAD;
Avuton Olrich's avatar
Avuton Olrich committed
672 673 674
		return -1;
	}

675 676 677
	switch (parse_response_code(is, response)) {
	case 200: /* OK */
	case 206: /* Partial Content */
Avuton Olrich's avatar
Avuton Olrich committed
678
		break;
679 680 681 682
	case 301: /* Moved Permanently */
	case 302: /* Moved Temporarily */
		if (parse_redirect(is, response, needle) == 0)
			return 0; /* success, reconnect */
Avuton Olrich's avatar
Avuton Olrich committed
683
	default:
684
		return err_close(data);
Avuton Olrich's avatar
Avuton Olrich committed
685 686
	}

687 688 689 690 691 692 693 694 695 696 697 698 699
	parse_headers(is, response, needle);
	if (is->size <= 0)
		is->seekable = 0;
	needle += sizeof("\r\n\r\n") - 1;
	peeked = needle - response;
	assert(peeked <= r);
	do {
		r = recv(data->fd, response, peeked, 0);
	} while (r < 0 && errno == EINTR);
	assert(r == peeked && "r != peeked");

	ringbuf_writer_reset(data->rb);
	data->state = CONN_STATE_PREBUFFER;
Max Kellermann's avatar
Max Kellermann committed
700
	is->ready = 1;
Avuton Olrich's avatar
Avuton Olrich committed
701

702 703
	return 0;
}
Warren Dukes's avatar
Warren Dukes committed
704

705 706 707 708 709
static void * http_io_task(void *arg)
{
	InputStream *is = (InputStream *) arg;
	struct http_data *data = (struct http_data *) is->data;

710
	cond_enter(&data->full_cond);
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
	while (1) {
		take_action(data);
		switch (data->state) {
		case CONN_STATE_NEW:
		case CONN_STATE_REDIRECT:
			init_connection(data);
			break;
		case CONN_STATE_CONNECTED:
			switch (await_sendable(data)) {
			case AWAIT_READY: send_request(is); break;
			case AWAIT_ACTION_PENDING: break;
			case AWAIT_ERROR: goto err;
			}
			break;
		case CONN_STATE_REQUESTED:
		case CONN_STATE_RESP_HEAD:
			switch (await_recvable(data)) {
			case AWAIT_READY: recv_response(is); break;
			case AWAIT_ACTION_PENDING: break;
			case AWAIT_ERROR: goto err;
			}
			break;
		case CONN_STATE_PREBUFFER:
		case CONN_STATE_BUFFER:
			switch (await_recvable(data)) {
			case AWAIT_READY: buffer_data(is); break;
			case AWAIT_ACTION_PENDING: break;
			case AWAIT_ERROR: goto err;
			}
			break;
		case CONN_STATE_BUFFER_FULL:
			await_buffer_space(data);
			break;
		case CONN_STATE_CLOSED: goto closed;
		}
	}
err:
	err_close(data);
closed:
	assert_state(CONN_STATE_CLOSED);
751
	cond_leave(&data->full_cond);
752 753
	return NULL;
}
754

755
int inputStream_httpBuffer(mpd_unused InputStream *is)
756
{
Avuton Olrich's avatar
Avuton Olrich committed
757
	return 0;
Warren Dukes's avatar
Warren Dukes committed
758 759
}

760
int inputStream_httpOpen(InputStream * is, char *url)
Avuton Olrich's avatar
Avuton Olrich committed
761
{
762 763
	struct http_data *data = new_http_data();
	pthread_attr_t attr;
Warren Dukes's avatar
Warren Dukes committed
764

765 766 767 768
	is->seekable = 0;
	is->data = data;
	if (parse_url(data, url) < 0) {
		free_http_data(data);
Avuton Olrich's avatar
Avuton Olrich committed
769 770
		return -1;
	}
Warren Dukes's avatar
Warren Dukes committed
771

772 773 774 775 776
	is->seekFunc = inputStream_httpSeek;
	is->closeFunc = inputStream_httpClose;
	is->readFunc = inputStream_httpRead;
	is->atEOFFunc = inputStream_httpAtEOF;
	is->bufferFunc = inputStream_httpBuffer;
Warren Dukes's avatar
Warren Dukes committed
777

778 779 780
	pthread_attr_init(&attr);
	if (pthread_create(&data->io_thread, &attr, http_io_task, is))
		FATAL("failed to spawn http_io_task: %s", strerror(errno));
Warren Dukes's avatar
Warren Dukes committed
781

782
	cond_enter(&data->empty_cond); /* httpClose will leave this */
Warren Dukes's avatar
Warren Dukes committed
783 784 785
	return 0;
}

786
int inputStream_httpSeek(InputStream * is, long offset, int whence)
Avuton Olrich's avatar
Avuton Olrich committed
787
{
788 789 790 791 792 793
	struct http_data *data = (struct http_data *)is->data;
	long old_offset = is->offset;
	long diff;

	if (!is->seekable) {
		is->error = ESPIPE;
794
		return -1;
795 796
	}
	assert(is->size > 0);
797

798 799
	switch (whence) {
	case SEEK_SET:
800
		is->offset = offset;
801 802
		break;
	case SEEK_CUR:
803
		is->offset += offset;
804 805
		break;
	case SEEK_END:
806
		is->offset = is->size + offset;
807 808
		break;
	default:
809
		is->error = EINVAL;
810
		return -1;
811
	}
Avuton Olrich's avatar
Avuton Olrich committed
812

813
	diff = is->offset - old_offset;
814 815
	if (!diff)
		return 0; /* nothing to seek */
816 817 818 819 820 821 822 823
	if (diff > 0) { /* seek forward if we've already buffered it */
		long avail = (long)ringbuf_read_space(data->rb);
		if (avail >= diff) {
			ringbuf_read_advance(data->rb, diff);
			return 0;
		}
	}
	trigger_action(data, CONN_ACTION_DOSEEK, 0);
824
	return 0;
Warren Dukes's avatar
Warren Dukes committed
825 826
}

827
static void parse_icy_metadata(InputStream * is, char *metadata, size_t size)
Warren Dukes's avatar
Warren Dukes committed
828
{
829
	char *r = NULL;
830 831 832 833 834 835 836 837 838 839 840 841 842 843 844 845 846
	char *cur;
	size_t offset;

	assert(size);
	metadata[size] = '\0';
	cur = strtok_r(metadata, ";", &r);
	while (cur) {
		if (match("StreamTitle=")) {
			if (is->metaTitle)
				free(is->metaTitle);
			if (cur[offset] == '\'')
				offset++;
			if (r[-2] == '\'')
				r[-2] = '\0';
			is->metaTitle = xstrdup(cur + offset);
			DEBUG(__FILE__ ": metaTitle: %s\n", is->metaTitle);
			return;
Warren Dukes's avatar
Warren Dukes committed
847
		}
848
		cur = strtok_r(NULL, ";", &r);
Warren Dukes's avatar
Warren Dukes committed
849 850 851
	}
}

852 853
static size_t read_with_metadata(InputStream *is, unsigned char *ptr,
				 ssize_t len)
Warren Dukes's avatar
Warren Dukes committed
854
{
855 856 857 858 859 860 861 862
	struct http_data *data = (struct http_data *) is->data;
	size_t readed = 0;
	size_t r;
	size_t to_read;
	assert(data->icy_metaint > 0);

	while (len > 0) {
		if (ringbuf_read_space(data->rb) < data->icy_metaint)
Avuton Olrich's avatar
Avuton Olrich committed
863
			break;
864 865 866 867 868 869 870
		if (data->icy_offset >= data->icy_metaint) {
			unsigned char metabuf[(UCHAR_MAX << 4) + 1];
			size_t metalen;
			r = ringbuf_read(data->rb, metabuf, 1);
			assert(r == 1 && "failed to read");
			awaken_buffer_task(data);
			metalen = *(metabuf);
Warren Dukes's avatar
Warren Dukes committed
871
			metalen <<= 4;
872 873 874 875
			if (metalen) {
				r = ringbuf_read(data->rb, metabuf, metalen);
				assert(r == metalen && "short metadata read");
				parse_icy_metadata(is, (char*)metabuf, metalen);
Warren Dukes's avatar
Warren Dukes committed
876
			}
877
			data->icy_offset = 0;
Warren Dukes's avatar
Warren Dukes committed
878
		}
879 880 881 882 883 884 885 886 887 888
		to_read = len;
		if (to_read > (data->icy_metaint - data->icy_offset))
			to_read = data->icy_metaint - data->icy_offset;
		if (!(r = ringbuf_read(data->rb, ptr, to_read)))
			break;
		awaken_buffer_task(data);
		len -= r;
		ptr += r;
		readed += r;
		data->icy_offset += r;
Avuton Olrich's avatar
Avuton Olrich committed
889
	}
890
	return readed;
891 892
}

893
size_t inputStream_httpRead(InputStream * is, void *_ptr, size_t size,
894
			    size_t nmemb)
Avuton Olrich's avatar
Avuton Olrich committed
895
{
896 897 898
	struct http_data *data = (struct http_data *) is->data;
	size_t len = size * nmemb;
	size_t r;
899
	unsigned char *ptr = _ptr, *ptr0 = _ptr;
900 901 902 903 904 905 906 907 908 909 910 911 912 913 914
	long tries = len / 128; /* try harder for bigger reads */

retry:
	switch (data->state) {
	case CONN_STATE_NEW:
	case CONN_STATE_REDIRECT:
	case CONN_STATE_CONNECTED:
	case CONN_STATE_REQUESTED:
	case CONN_STATE_RESP_HEAD:
	case CONN_STATE_PREBUFFER:
		if ((starved_wait(data, 1) == 0) || (tries-- > 0))
			goto retry; /* success */
		return 0;
	case CONN_STATE_BUFFER:
	case CONN_STATE_BUFFER_FULL:
Avuton Olrich's avatar
Avuton Olrich committed
915
		break;
916 917 918
	case CONN_STATE_CLOSED:
		if (!ringbuf_read_space(data->rb))
			return 0;
Avuton Olrich's avatar
Avuton Olrich committed
919
	}
920

921 922 923 924 925 926 927 928 929 930 931 932 933 934 935 936 937 938 939 940
	while (1) {
		if (data->icy_metaint > 0)
			r = read_with_metadata(is, ptr, len);
		else /* easy, no metadata to worry about */
			r = ringbuf_read(data->rb, ptr, len);
		assert(r <= len);
		if (r) {
			awaken_buffer_task(data);
			is->offset += r;
			ptr += r;
			len -= r;
		}
		if (!len || (--tries < 0) ||
		    (data->state == CONN_STATE_CLOSED &&
		     !ringbuf_read_space(data->rb)))
			break;
		starved_wait(data, 1);
	}
	return (ptr - ptr0) / size;
}
941

942 943 944 945 946 947 948 949 950 951 952 953
int inputStream_httpClose(InputStream * is)
{
	struct http_data *data = (struct http_data *) is->data;

	/*
	 * The cancellation routines in pthreads suck (and
	 * are probably unportable) and using signal handlers
	 * between threads is _definitely_ unportable.
	 */
	while (data->state != CONN_STATE_CLOSED)
		trigger_action(data, CONN_ACTION_CLOSE, 1);
	pthread_join(data->io_thread, NULL);
954
	cond_leave(&data->empty_cond);
955
	free_http_data(data);
Avuton Olrich's avatar
Avuton Olrich committed
956
	return 0;
957 958
}

959
int inputStream_httpAtEOF(InputStream * is)
Avuton Olrich's avatar
Avuton Olrich committed
960
{
961 962 963 964
	struct http_data *data = (struct http_data *) is->data;
	if (data->state == CONN_STATE_CLOSED && !ringbuf_read_space(data->rb))
		return 1;
	return 0;
965 966
}

967
void inputStream_initHttp(void)
Avuton Olrich's avatar
Avuton Olrich committed
968
{
969 970 971 972
	ConfigParam *param = getConfigParam(CONF_HTTP_PROXY_HOST);
	char *test;
	if (param) {
		proxy_host = param->value;
Warren Dukes's avatar
Warren Dukes committed
973

974
		param = getConfigParam(CONF_HTTP_PROXY_PORT);
Warren Dukes's avatar
Warren Dukes committed
975

976 977 978 979 980
		if (!param) {
			FATAL("%s specified but not %s\n", CONF_HTTP_PROXY_HOST,
			      CONF_HTTP_PROXY_PORT);
		}
		proxy_port = param->value;
Warren Dukes's avatar
Warren Dukes committed
981

982 983 984 985 986 987 988 989 990 991 992 993 994 995 996 997 998 999 1000 1001 1002 1003 1004 1005 1006 1007 1008 1009 1010 1011 1012 1013
		param = getConfigParam(CONF_HTTP_PROXY_USER);

		if (param) {
			proxy_user = param->value;

			param = getConfigParam(CONF_HTTP_PROXY_PASSWORD);

			if (!param) {
				FATAL("%s specified but not %s\n",
				      CONF_HTTP_PROXY_USER,
				      CONF_HTTP_PROXY_PASSWORD);
			}

			proxy_password = param->value;
		} else {
			param = getConfigParam(CONF_HTTP_PROXY_PASSWORD);

			if (param) {
				FATAL("%s specified but not %s\n",
				      CONF_HTTP_PROXY_PASSWORD, CONF_HTTP_PROXY_USER);
			}
		}
	} else if ((param = getConfigParam(CONF_HTTP_PROXY_PORT))) {
		FATAL("%s specified but not %s, line %i\n",
		      CONF_HTTP_PROXY_PORT, CONF_HTTP_PROXY_HOST, param->line);
	} else if ((param = getConfigParam(CONF_HTTP_PROXY_USER))) {
		FATAL("%s specified but not %s, line %i\n",
		      CONF_HTTP_PROXY_USER, CONF_HTTP_PROXY_HOST, param->line);
	} else if ((param = getConfigParam(CONF_HTTP_PROXY_PASSWORD))) {
		FATAL("%s specified but not %s, line %i\n",
		      CONF_HTTP_PROXY_PASSWORD, CONF_HTTP_PROXY_HOST,
		      param->line);
Avuton Olrich's avatar
Avuton Olrich committed
1014
	}
Warren Dukes's avatar
Warren Dukes committed
1015

1016 1017 1018 1019 1020 1021 1022 1023 1024 1025 1026
	param = getConfigParam(CONF_HTTP_BUFFER_SIZE);

	if (param) {
		long tmp = strtol(param->value, &test, 10);
		if (*test != '\0' || tmp <= 0) {
			FATAL("\"%s\" specified for %s at line %i is not a "
			      "positive integer\n",
			      param->value, CONF_HTTP_BUFFER_SIZE, param->line);
		}

		buffer_size = tmp * 1024;
Avuton Olrich's avatar
Avuton Olrich committed
1027
	}
1028 1029
	if (buffer_size < 4096)
		FATAL(CONF_HTTP_BUFFER_SIZE" must be >= 4KB\n");
Warren Dukes's avatar
Warren Dukes committed
1030

1031
	param = getConfigParam(CONF_HTTP_PREBUFFER_SIZE);
1032

1033 1034 1035 1036 1037 1038 1039 1040 1041 1042 1043 1044 1045 1046 1047 1048
	if (param) {
		long tmp = strtol(param->value, &test, 10);
		if (*test != '\0' || tmp <= 0) {
			FATAL("\"%s\" specified for %s at line %i is not a "
			      "positive integer\n",
			      param->value, CONF_HTTP_PREBUFFER_SIZE,
			      param->line);
		}

		prebuffer_size = tmp * 1024;
	}

	if (prebuffer_size > buffer_size)
		prebuffer_size = buffer_size;
	assert(buffer_size > 0 && "http buffer_size too small");
	assert(prebuffer_size > 0 && "http prebuffer_size too small");
Warren Dukes's avatar
Warren Dukes committed
1049
}
1050