summaryrefslogtreecommitdiff
path: root/src/input/input_http.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/input/input_http.c')
-rw-r--r--src/input/input_http.c85
1 files changed, 63 insertions, 22 deletions
diff --git a/src/input/input_http.c b/src/input/input_http.c
index 3adbc836b..5673a74b2 100644
--- a/src/input/input_http.c
+++ b/src/input/input_http.c
@@ -64,13 +64,13 @@
#define TAG_ICY_NOTICE2 "icy-notice2:"
#define TAG_ICY_METAINT "icy-metaint:"
#define TAG_CONTENT_TYPE "Content-Type:"
+#define TAG_LASTFM_SERVER "Server: last.fm Streaming Server"
typedef struct {
input_plugin_t input_plugin;
xine_stream_t *stream;
- int fh;
char *mrl;
nbc_t *nbc;
@@ -84,25 +84,30 @@ typedef struct {
char auth[BUFSIZE];
char proxyauth[BUFSIZE];
+ char preview[MAX_PREVIEW_SIZE];
+ off_t preview_size;
+
char *proto;
char *user;
char *password;
char *host;
- int port;
char *uri;
-
- char preview[MAX_PREVIEW_SIZE];
- off_t preview_size;
-
+ int port;
+
+ int fh;
+
+ /** Set to 1 if the stream is a NSV stream. */
+ int is_nsv:1;
+ /** Set to 1 if the stream comes from last.fm. */
+ int is_lastfm:1;
+ /** Set to 1 if the stream is ShoutCast. */
+ int shoutcast_mode:1;
+
/* ShoutCast */
- int shoutcast_mode;
int shoutcast_metaint;
off_t shoutcast_pos;
char *shoutcast_songtitle;
- /* NSV */
- int is_nsv;
-
/* scratch buffer for forward seeking */
char seek_buf[BUFSIZE];
@@ -117,13 +122,13 @@ typedef struct {
config_values_t *config;
char *proxyhost;
+ char *proxyhost_env;
int proxyport;
+ int proxyport_env;
+
char *proxyuser;
char *proxypassword;
char *noproxylist;
-
- char *proxyhost_env;
- int proxyport_env;
} http_input_class_t;
static void proxy_host_change_cb (void *this_gen, xine_cfg_entry_t *cfg) {
@@ -181,7 +186,7 @@ static int _x_use_proxy(http_input_class_t *this, const char *host) {
/* \177\0\0\1 is the *octal* representation of 127.0.0.1 */
if ( info->h_addrtype == AF_INET && !memcmp(info->h_addr_list[0], "\177\0\0\1", 4) ) {
lprintf("host '%s' is localhost\n", host);
- return 1;
+ return 0;
}
/* TODO: IPv6 check */
}
@@ -200,13 +205,13 @@ static int _x_use_proxy(http_input_class_t *this, const char *host) {
/* special-case domain beginning with '=' -> is a host name */
if (domain[0] == '=' && strcmp(target, domain + 1) == 0) {
lprintf("host '%s' is in no-proxy domain '%s'\n", target, domain);
- return 1;
+ return 0;
}
noprox_len = strlen(domain);
/* special-case host==domain, avoiding dot checks */
if (host_len == noprox_len && strcmp(target, domain) == 0) {
lprintf("host '%s' is in no-proxy domain '%s'\n", target, domain);
- return 1;
+ return 0;
}
/* check for host in domain, and require that (if matched) the domain
* name is preceded by a dot, either in the host or domain strings,
@@ -216,7 +221,7 @@ static int _x_use_proxy(http_input_class_t *this, const char *host) {
&& (domain[0] == '.' || target[host_len - noprox_len - 1] == '.')
&& strcmp(target + host_len - noprox_len, domain) == 0) {
lprintf("host '%s' is in no-proxy domain '%s'\n", target, domain);
- return 1;
+ return 0;
}
lprintf("host '%s' isn't in no-proxy domain '%s'\n", target, domain);
}
@@ -225,7 +230,7 @@ static int _x_use_proxy(http_input_class_t *this, const char *host) {
}
free(no_proxy);
- return 0;
+ return 1;
}
static int http_plugin_basicauth (const char *user, const char *password, char* dest, int len) {
@@ -383,6 +388,25 @@ static off_t http_plugin_read_int (http_input_plugin_t *this,
if (nlen < 0)
goto error;
+ /* Identify SYNC string for last.fm, this is limited to last.fm
+ * streaming servers to avoid hitting on tracks metadata for other
+ * servers.
+ */
+ if ( this->is_lastfm &&
+ memmem(&buf[read_bytes], nlen, "SYNC", 4) != NULL ) {
+ /* Tell frontend to update the UI */
+ const xine_event_t event = {
+ .type = XINE_EVENT_UI_CHANNELS_CHANGED,
+ .stream = this->stream,
+ .data = NULL,
+ .data_length = 0
+ };
+
+ lprintf("SYNC from last.fm server received\n");
+
+ xine_event_send(this->stream, &event);
+ }
+
this->shoutcast_pos += nlen;
}
@@ -402,8 +426,9 @@ error:
}
static off_t http_plugin_read (input_plugin_t *this_gen,
- char *buf, off_t nlen) {
+ void *buf_gen, off_t nlen) {
http_input_plugin_t *this = (http_input_plugin_t *) this_gen;
+ char *buf = (char *)buf_gen;
off_t n, num_bytes;
num_bytes = 0;
@@ -663,9 +688,8 @@ static int http_plugin_open (input_plugin_t *this_gen ) {
_x_message(this->stream, XINE_MSG_GENERAL_WARNING, "malformed url", NULL);
return 0;
}
- if (use_proxy && _x_use_proxy(this_class, this->host)) {
- use_proxy = 0;
- }
+ use_proxy = use_proxy && _x_use_proxy(this_class, this->host);
+
if (this->port == 0)
this->port = DEFAULT_HTTP_PORT;
@@ -830,6 +854,11 @@ static int http_plugin_open (input_plugin_t *this_gen ) {
_("input_http: http status not 2xx: >%d %s<\n"),
httpcode, httpstatus);
return -7;
+ } else if (httpcode == 401) {
+ xine_log (this->stream->xine, XINE_LOG_MSG,
+ _("input_http: http status not 2xx: >%d %s<\n"),
+ httpcode, httpstatus);
+ /* don't return - there may be a WWW-Authenticate header... */
} else if (httpcode == 403) {
_x_message(this->stream, XINE_MSG_PERMISSION_ERROR, this->mrl, NULL);
xine_log (this->stream->xine, XINE_LOG_MSG,
@@ -867,6 +896,10 @@ static int http_plugin_open (input_plugin_t *this_gen ) {
return http_plugin_open(this_gen);
}
+ if (!strncasecmp (this->buf, "WWW-Authenticate: ", 18))
+ strcpy (this->preview, this->buf + 18);
+
+
/* Icecast / ShoutCast Stuff */
if (!strncasecmp(this->buf, TAG_ICY_NAME, sizeof(TAG_ICY_NAME) - 1)) {
_x_meta_info_set(this->stream, XINE_META_INFO_ALBUM,
@@ -908,6 +941,10 @@ static int http_plugin_open (input_plugin_t *this_gen ) {
this->is_nsv = 1;
}
}
+ if ( !strncasecmp(this->buf, TAG_LASTFM_SERVER, sizeof(TAG_LASTFM_SERVER)-1) ) {
+ lprintf("last.fm streaming server detected\n");
+ this->is_lastfm = 1;
+ }
}
if (len == -1)
@@ -926,6 +963,10 @@ static int http_plugin_open (input_plugin_t *this_gen ) {
lprintf ("end of headers\n");
+ if (httpcode == 401)
+ _x_message(this->stream, XINE_MSG_AUTHENTICATION_NEEDED,
+ this->mrl, *this->preview ? this->preview : NULL, NULL);
+
/*
* fill preview buffer
*/