diff options
Diffstat (limited to 'src/input/input_http.c')
-rw-r--r-- | src/input/input_http.c | 211 |
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 } }; |