You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
tdemultimedia/mpg123_artsplugin/mpg123/httpget.c

482 lines
10 KiB

/*
* httpget.c
*
* Oliver Fromme <oliver.fromme@heim3.tu-clausthal.de>
* Wed Apr 9 20:57:47 MET DST 1997
*/
#undef ALSA
#if !defined(WIN32) && !defined(GENERIC)
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <netdb.h>
#include <sys/param.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <sys/errno.h>
#include <ctype.h>
extern int errno;
#include "mpg123.h"
#ifndef INADDR_NONE
#define INADDR_NONE 0xffffffff
#endif
void writestring (int fd, char *string)
{
int result, bytes = strlen(string);
while (bytes) {
if ((result = write(fd, string, bytes)) < 0 && errno != EINTR) {
perror ("write");
exit (1);
}
else if (result == 0) {
fprintf (stderr, "write: %s\n",
"socket closed unexpectedly");
exit (1);
}
string += result;
bytes -= result;
}
}
void readstring (char *string, int maxlen, FILE *f)
{
#if 0
char *result;
#endif
int pos = 0;
while(1) {
if( read(fileno(f),string+pos,1) == 1) {
pos++;
if(string[pos-1] == '\n') {
string[pos] = 0;
break;
}
}
else if(errno != EINTR) {
fprintf (stderr, "Error reading from socket or unexpected EOF.\n");
exit(1);
}
}
#if 0
do {
result = fgets(string, maxlen, f);
} while (!result && errno == EINTR);
if (!result) {
fprintf (stderr, "Error reading from socket or unexpected EOF.\n");
exit (1);
}
#endif
}
void encode64 (char *source,char *destination)
{
static char *Base64Digits =
"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
int n = 0;
int ssiz=strlen(source);
int i;
for (i = 0 ; i < ssiz ; i += 3) {
unsigned int buf;
buf = ((unsigned char *)source)[i] << 16;
if (i+1 < ssiz)
buf |= ((unsigned char *)source)[i+1] << 8;
if (i+2 < ssiz)
buf |= ((unsigned char *)source)[i+2];
destination[n++] = Base64Digits[(buf >> 18) % 64];
destination[n++] = Base64Digits[(buf >> 12) % 64];
if (i+1 < ssiz)
destination[n++] = Base64Digits[(buf >> 6) % 64];
else
destination[n++] = '=';
if (i+2 < ssiz)
destination[n++] = Base64Digits[buf % 64];
else
destination[n++] = '=';
}
destination[n++] = 0;
}
/* VERY simple auth-from-URL grabber */
int getauthfromURL(char *url,char *auth)
{
char *pos;
*auth = 0;
if (!(strncasecmp(url, "http://", 7)))
url += 7;
if (!(strncasecmp(url, "ftp://", 6)))
url += 6;
if( (pos = strchr(url,'@')) ) {
int i;
for(i=0;i<pos-url;i++) {
if( url[i] == '/' )
return 0;
}
strncpy(auth,url,pos-url);
auth[pos-url] = 0;
strcpy(url,pos+1);
return 1;
}
return 0;
}
static char *defaultportstr = "80";
char *url2hostport (char *url, char **hname, unsigned long *hip, unsigned char **port)
{
char *h, *p;
char *hostptr;
char *r_hostptr;
char *pathptr;
char *portptr;
char *p0;
size_t stringlength;
p = url;
if (strncasecmp(p, "http://", 7) == 0)
p += 7;
if (strncasecmp(p, "ftp://", 6) == 0)
p += 6;
hostptr = p;
while (*p && *p != '/')
p++;
pathptr = p;
r_hostptr = --p;
while (*p && hostptr < p && *p != ':' && *p != ']')
p--;
if (!*p || p < hostptr || *p != ':') {
portptr = NULL;
}
else{
portptr = p + 1;
r_hostptr = p - 1;
}
if (*hostptr == '[' && *r_hostptr == ']') {
hostptr++;
r_hostptr--;
}
stringlength = r_hostptr - hostptr + 1;
h = malloc(stringlength + 1); /* removed the strndup for better portability */
if (h == NULL) {
*hname = NULL;
*port = NULL;
return NULL;
}
strncpy(h, hostptr, stringlength);
*(h+stringlength) = '\0';
*hname = h;
if (portptr) {
stringlength = (pathptr - portptr);
if(!stringlength) portptr = NULL;
}
if (portptr == NULL) {
portptr = defaultportstr;
stringlength = strlen(defaultportstr);
}
p0 = malloc(stringlength + 1);
if (p0 == NULL) {
free(h);
*hname = NULL;
*port = NULL;
return NULL;
}
strncpy(p0, portptr, stringlength);
*(p0 + stringlength) = '\0';
for (p = p0; *p && isdigit((unsigned char) *p); p++) ;
*p = '\0';
*port = (unsigned char *) p0;
return pathptr;
}
char *proxyurl = NULL;
unsigned long proxyip = 0;
unsigned char *proxyport;
#define ACCEPT_HEAD "Accept: audio/mpeg, audio/x-mpegurl, */*\r\n"
char *httpauth = NULL;
char httpauth1[256];
int http_open (const char *url)
{
char *purl, *host, *request, *sptr;
int linelength;
unsigned long myip;
unsigned char *myport;
int sock;
int relocate, numrelocs = 0;
FILE *myfile;
#ifdef INET6
struct addrinfo hints, *res, *res0;
int error;
#else
struct hostent *hp;
struct sockaddr_in sin;
#endif
host = NULL;
proxyport = NULL;
myport = NULL;
if (!proxyip) {
if (!proxyurl)
if (!(proxyurl = getenv("MP3_HTTP_PROXY")))
if (!(proxyurl = getenv("http_proxy")))
proxyurl = getenv("HTTP_PROXY");
if (proxyurl && proxyurl[0] && strcmp(proxyurl, "none")) {
if (!(url2hostport(proxyurl, &host, &proxyip, &proxyport))) {
fprintf (stderr, "Unknown proxy host \"%s\".\n",
host ? host : "");
exit (1);
}
#if 0
if (host)
free (host);
#endif
}
else
proxyip = INADDR_NONE;
}
if (proxyip == INADDR_NONE)
if (strncasecmp(url, "ftp://", 6) == 0){
fprintf(stderr,"Downloading from ftp servers without PROXY not allowed\n");
exit(1);
}
if ((linelength = strlen(url)+200) < 1024)
linelength = 1024;
if (!(request = malloc(linelength)) || !(purl = malloc(1024))) {
fprintf (stderr, "malloc() failed, out of memory.\n");
exit (1);
}
/*
* 2000-10-21:
* We would like spaces to be automatically converted to %20's when
* fetching via HTTP.
* -- Martin Sj<53>gren <md9ms@mdstud.chalmers.se>
*/
if ((sptr = strchr(url, ' ')) == NULL) {
strncpy (purl, url, 1023);
purl[1023] = '\0';
}
else {
int purllength = 0;
char *urlptr = url;
purl[0] = '\0';
do {
purllength += sptr-urlptr + 3;
if (purllength >= 1023)
break;
strncat (purl, urlptr, sptr-urlptr);
/*purl[sptr-url] = '\0';*/
strcat (purl, "%20");
urlptr = sptr + 1;
}
while ((sptr = strchr (urlptr, ' ')) != NULL);
strcat (purl, urlptr);
}
getauthfromURL(purl,httpauth1);
do {
strcpy (request, "GET ");
if (proxyip != INADDR_NONE) {
if (strncasecmp(url, "http://", 7) != 0 && strncasecmp(url,"ftp://", 6) != 0)
strcat (request, "http://");
strcat (request, purl);
myport = proxyport;
myip = proxyip;
}
else {
if (host) {
free(host);
host=NULL;
}
if (proxyport) {
free(proxyport);
proxyport=NULL;
}
if (!(sptr = url2hostport(purl, &host, &myip, &myport))) {
fprintf (stderr, "Unknown host \"%s\".\n",
host ? host : "");
exit (1);
}
strcat (request, sptr);
}
sprintf (request + strlen(request),
" HTTP/1.0\r\nUser-Agent: %s/%s\r\n",
prgName, prgVersion);
if (host) {
sprintf(request + strlen(request),
"Host: %s:%s\r\n", host, myport);
#if 0
free (host);
#endif
}
strcat (request, ACCEPT_HEAD);
#ifdef INET6
memset(&hints, 0, sizeof(hints));
hints.ai_socktype = SOCK_STREAM;
error = getaddrinfo(host, (char *)myport, &hints, &res0);
if (error) {
fprintf(stderr, "getaddrinfo: %s\n", gai_strerror(error));
exit(1);
}
sock = -1;
for (res = res0; res; res = res->ai_next) {
if ((sock = socket(res->ai_family, res->ai_socktype, res->ai_protocol)) < 0) {
continue;
}
if (connect(sock, res->ai_addr, res->ai_addrlen)) {
close(sock);
sock = -1;
continue;
}
break;
}
freeaddrinfo(res0);
#else
sock = -1;
hp = gethostbyname(host);
if (!hp)
goto fail;
if (hp->h_length != sizeof(sin.sin_addr))
goto fail;
sock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
if (sock < 0)
goto fail;
memset(&sin, 0, sizeof(sin));
sin.sin_family = AF_INET;
/* sin.sin_len = sizeof(struct sockaddr_in); */
memcpy(&sin.sin_addr, hp->h_addr, hp->h_length);
sin.sin_port = htons(atoi( (char *) myport));
if (connect(sock, (struct sockaddr *)&sin, sizeof(struct sockaddr_in) ) < 0) {
close(sock);
sock = -1;
}
fail:
#endif
if (sock < 0) {
perror("socket");
exit(1);
}
if (strlen(httpauth1) || httpauth) {
char buf[1023];
strcat (request,"Authorization: Basic ");
if(strlen(httpauth1))
encode64(httpauth1,buf);
else
encode64(httpauth,buf);
strcat (request,buf);
strcat (request,"\r\n");
}
strcat (request, "\r\n");
writestring (sock, request);
if (!(myfile = fdopen(sock, "rb"))) {
perror ("fdopen");
exit (1);
};
relocate = FALSE;
purl[0] = '\0';
readstring (request, linelength-1, myfile);
if ((sptr = strchr(request, ' '))) {
switch (sptr[1]) {
case '3':
relocate = TRUE;
case '2':
break;
default:
fprintf (stderr, "HTTP request failed: %s",
sptr+1); /* '\n' is included */
exit (1);
}
}
do {
readstring (request, linelength-1, myfile);
if (!strncmp(request, "Location:", 9))
strncpy (purl, request+10, 1023);
} while (request[0] != '\r' && request[0] != '\n');
} while (relocate && purl[0] && numrelocs++ < 5);
if (relocate) {
fprintf (stderr, "Too many HTTP relocations.\n");
exit (1);
}
free (purl);
free (request);
free(host);
free(proxyport);
free(myport);
return sock;
}
#else
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
extern int errno;
#include "mpg123.h"
void writestring (int fd, char *string)
{
}
void readstring (char *string, int maxlen, FILE *f)
{
}
char *url2hostport (char *url, char **hname, unsigned long *hip, unsigned int *port)
{
}
char *proxyurl = NULL;
unsigned long proxyip = 0;
unsigned int proxyport;
#define ACCEPT_HEAD "Accept: audio/mpeg, audio/x-mpegurl, */*\r\n"
int http_open (char *url)
{
}
#endif
/* EOF */