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.c211
1 files changed, 87 insertions, 124 deletions
diff --git a/src/input/input_http.c b/src/input/input_http.c
index aec74bd5d..34437c976 100644
--- a/src/input/input_http.c
+++ b/src/input/input_http.c
@@ -40,15 +40,21 @@
#include <sys/time.h>
+#ifdef HAVE_FFMPEG_AVUTIL_H
+# include <base64.h>
+#else
+# include <libavutil/base64.h>
+#endif
+
#define LOG_MODULE "input_http"
#define LOG_VERBOSE
/*
#define LOG
*/
-#include "xine_internal.h"
-#include "xineutils.h"
-#include "input_plugin.h"
+#include <xine/xine_internal.h>
+#include <xine/xineutils.h>
+#include <xine/input_plugin.h>
#include "net_buf_ctrl.h"
#include "http_helper.h"
@@ -69,7 +75,6 @@ typedef struct {
xine_stream_t *stream;
- int fh;
char *mrl;
nbc_t *nbc;
@@ -78,37 +83,33 @@ typedef struct {
off_t contentlength;
char buf[BUFSIZE];
- char proxybuf[BUFSIZE];
- char auth[BUFSIZE];
- char proxyauth[BUFSIZE];
+ char preview[MAX_PREVIEW_SIZE];
+ off_t preview_size;
char *mime_type;
-
+ const char *user_agent;
char *proto;
char *user;
char *password;
char *host;
- int port;
char *uri;
+ int port;
- const char *user_agent;
-
- char preview[MAX_PREVIEW_SIZE];
- off_t preview_size;
+ int fh;
- /* Last.FM streaming server */
- unsigned char is_lastfm;
+ /** 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];
@@ -123,13 +124,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) {
@@ -168,7 +169,7 @@ static void no_proxy_list_change_cb(void *this_gen, xine_cfg_entry_t *cfg) {
*/
static int _x_use_proxy(http_input_class_t *this, const char *host) {
const char *target;
- char *no_proxy, *domain, *ptr;
+ char *no_proxy, *domain, *ptr = NULL;
struct hostent *info;
size_t i = 0, host_len, noprox_len;
@@ -234,51 +235,15 @@ static int _x_use_proxy(http_input_class_t *this, const char *host) {
return 1;
}
-static int http_plugin_basicauth (const char *user, const char *password, char* dest, int len) {
- static char *enctable="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=";
- char *tmp;
- char *sptr;
- char *dptr;
- size_t count;
- int enclen;
+static void http_plugin_basicauth (const char *user, const char *password, char** dest) {
+ const size_t totlen = strlen(user) + (password ? strlen(password) : 0) + 1;
+ const size_t enclen = ((totlen + 2) * 4 ) / 3 + 12;
+ char tmp[totlen + 1];
- count = asprintf(&tmp, "%s:%s", user, (password != NULL) ? password : "");
+ snprintf(tmp, totlen + 1, "%s:%s", user, password ? : "");
- enclen = ((count + 2) / 3 ) * 4 + 1;
-
- if (len < enclen)
- return -1;
-
- sptr = tmp;
- dptr = dest;
- while (count >= 3) {
- dptr[0] = enctable[(sptr[0] & 0xFC) >> 2];
- dptr[1] = enctable[((sptr[0] & 0x3) << 4) | ((sptr[1] & 0xF0) >> 4)];
- dptr[2] = enctable[((sptr[1] & 0x0F) << 2) | ((sptr[2] & 0xC0) >> 6)];
- dptr[3] = enctable[sptr[2] & 0x3F];
- count -= 3;
- sptr += 3;
- dptr += 4;
- }
-
- if (count > 0) {
- dptr[0] = enctable[(sptr[0] & 0xFC) >> 2];
- dptr[1] = enctable[(sptr[0] & 0x3) << 4];
- dptr[2] = '=';
-
- if (count > 1) {
- dptr[1] = enctable[((sptr[0] & 0x3) << 4) | ((sptr[1] & 0xF0) >> 4)];
- dptr[2] = enctable[(sptr[1] & 0x0F) << 2];
- }
-
- dptr[3] = '=';
- dptr += 4;
- }
-
- dptr[0] = '\0';
-
- free(tmp);
- return 0;
+ *dest = malloc(enclen);
+ av_base64_encode(*dest, enclen, tmp, totlen);
}
static int http_plugin_read_metainf (http_input_plugin_t *this) {
@@ -417,8 +382,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;
@@ -644,7 +610,6 @@ static void http_plugin_dispose (input_plugin_t *this_gen ) {
if (this->user) free(this->user);
if (this->password) free(this->password);
if (this->uri) free(this->uri);
- if (this->mime_type) free(this->mime_type);
free (this);
}
@@ -678,18 +643,6 @@ static int http_plugin_open (input_plugin_t *this_gen ) {
mime_type[0] = 0;
use_proxy = this_class->proxyhost && strlen(this_class->proxyhost);
- if (use_proxy) {
- if (this_class->proxyuser && strlen(this_class->proxyuser)) {
- if (http_plugin_basicauth (this_class->proxyuser,
- this_class->proxypassword,
- this->proxyauth, BUFSIZE)) {
- _x_message(this->stream, XINE_MSG_CONNECTION_REFUSED, "proxy error", NULL);
- return 0;
- }
- }
- }
-
-
if (!_x_parse_url(this->mrl, &this->proto, &this->host, &this->port,
&this->user, &this->password, &this->uri,
&this->user_agent)) {
@@ -701,13 +654,6 @@ static int http_plugin_open (input_plugin_t *this_gen ) {
if (this->port == 0)
this->port = DEFAULT_HTTP_PORT;
- if (this->user && strlen(this->user)) {
- if (http_plugin_basicauth (this->user, this->password, this->auth, BUFSIZE)) {
- _x_message(this->stream, XINE_MSG_CONNECTION_REFUSED, "basic auth error", NULL);
- return -1;
- }
- }
-
if (this_class->proxyport == 0)
proxyport = DEFAULT_HTTP_PORT;
else
@@ -764,40 +710,54 @@ static int http_plugin_open (input_plugin_t *this_gen ) {
if (use_proxy) {
if (this->port != DEFAULT_HTTP_PORT) {
- buflen = snprintf (this->buf, BUFSIZE, "GET http://%s:%d%s HTTP/1.0\015\012",
- this->host, this->port, this->uri);
+ snprintf (this->buf, BUFSIZE, "GET http://%s:%d%s HTTP/1.0\015\012",
+ this->host, this->port, this->uri);
} else {
- buflen = snprintf (this->buf, BUFSIZE, "GET http://%s%s HTTP/1.0\015\012",
- this->host, this->uri);
+ snprintf (this->buf, BUFSIZE, "GET http://%s%s HTTP/1.0\015\012",
+ this->host, this->uri);
}
}
else
- buflen = snprintf (this->buf, BUFSIZE, "GET %s HTTP/1.0\015\012", this->uri);
+ snprintf (this->buf, BUFSIZE, "GET %s HTTP/1.0\015\012", this->uri);
+ buflen = strlen(this->buf);
if (this->port != DEFAULT_HTTP_PORT)
- buflen += snprintf (this->buf + buflen, BUFSIZE - buflen, "Host: %s:%d\015\012",
- this->host, this->port);
+ snprintf (this->buf + buflen, BUFSIZE - buflen, "Host: %s:%d\015\012",
+ this->host, this->port);
else
- buflen += snprintf (this->buf + buflen, BUFSIZE - buflen, "Host: %s\015\012",
- this->host);
-
- if (this_class->proxyuser && strlen(this_class->proxyuser)) {
- buflen += snprintf (this->buf + buflen, BUFSIZE - buflen,
- "Proxy-Authorization: Basic %s\015\012", this->proxyauth);
+ snprintf (this->buf + buflen, BUFSIZE - buflen, "Host: %s\015\012",
+ this->host);
+
+ buflen = strlen(this->buf);
+ if (use_proxy && this_class->proxyuser && strlen(this_class->proxyuser)) {
+ char *proxyauth;
+ http_plugin_basicauth (this_class->proxyuser, this_class->proxypassword,
+ &proxyauth);
+
+ snprintf (this->buf + buflen, BUFSIZE - buflen,
+ "Proxy-Authorization: Basic %s\015\012", proxyauth);
+ buflen = strlen(this->buf);
+ free(proxyauth);
}
if (this->user && strlen(this->user)) {
- buflen += snprintf (this->buf + buflen, BUFSIZE - buflen,
- "Authorization: Basic %s\015\012", this->auth);
+ char *auth;
+ http_plugin_basicauth (this->user, this->password, &auth);
+
+ snprintf (this->buf + buflen, BUFSIZE - buflen,
+ "Authorization: Basic %s\015\012", auth);
+ buflen = strlen(this->buf);
+ free(auth);
}
- buflen += snprintf(this->buf + buflen, BUFSIZE - buflen,
- "User-Agent: %s%sxine/%s\015\012"
- "Accept: */*\015\012"
- "Icy-MetaData: 1\015\012"
- "\015\012",
- this->user_agent ? this->user_agent : "",
- this->user_agent ? " " : "",
- VERSION);
+ snprintf(this->buf + buflen, BUFSIZE - buflen,
+ "User-Agent: %s%sxine/%s\015\012"
+ "Accept: */*\015\012"
+ "Icy-MetaData: 1\015\012"
+ "\015\012",
+ this->user_agent ? this->user_agent : "",
+ this->user_agent ? " " : "",
+ VERSION);
+ buflen = strlen(this->buf);
if (_x_io_tcp_write (this->stream, this->fh, this->buf, buflen) != buflen) {
_x_message(this->stream, XINE_MSG_CONNECTION_REFUSED, "couldn't send request", NULL);
xprintf(this_class->xine, XINE_VERBOSITY_DEBUG, "input_http: couldn't send request\n");
@@ -859,7 +819,12 @@ 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 == 403 || httpcode == 401) {
+ } 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,
_("input_http: http status not 2xx: >%d %s<\n"),
@@ -896,6 +861,9 @@ 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);
+
{
static const char mpegurl_ct_str[] = "Content-Type: audio/x-mpegurl";
static const size_t mpegurl_ct_size = sizeof(mpegurl_ct_str)-1;
@@ -973,6 +941,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);
+
if ( mpegurl_redirect ) {
char buf[4096] = { 0, };
char *newline = NULL;
@@ -1066,19 +1038,10 @@ static input_plugin_t *http_class_get_instance (input_class_t *cls_gen, xine_str
return &this->input_plugin;
}
-static const char *http_class_get_description (input_class_t *this_gen) {
- return _("http input plugin");
-}
-
-static const char *http_class_get_identifier (input_class_t *this_gen) {
- return "http";
-}
-
static void http_class_dispose (input_class_t *this_gen) {
http_input_class_t *this = (http_input_class_t *) this_gen;
- if(this->proxyhost_env)
- free(this->proxyhost_env);
+ free(this->proxyhost_env);
free (this);
}
@@ -1095,8 +1058,8 @@ static void *init_class (xine_t *xine, void *data) {
config = xine->config;
this->input_class.get_instance = http_class_get_instance;
- this->input_class.get_identifier = http_class_get_identifier;
- this->input_class.get_description = http_class_get_description;
+ this->input_class.identifier = "http";
+ this->input_class.description = N_("http input plugin");
this->input_class.get_dir = NULL;
this->input_class.get_autoplay_list = NULL;
this->input_class.dispose = http_class_dispose;
@@ -1164,6 +1127,6 @@ static void *init_class (xine_t *xine, void *data) {
const plugin_info_t xine_plugin_info[] EXPORTED = {
/* type, API, "name", version, special_info, init_function */
- { PLUGIN_INPUT | PLUGIN_MUST_PRELOAD, 17, "http", XINE_VERSION_CODE, NULL, init_class },
+ { PLUGIN_INPUT | PLUGIN_MUST_PRELOAD, 18, "http", XINE_VERSION_CODE, NULL, init_class },
{ PLUGIN_NONE, 0, "", 0, NULL, NULL }
};