📄 httpget.c
字号:
/* httpget.c: http communication copyright ?-2006 by the mpg123 project - free software under the terms of the LGPL 2.1 see COPYING and AUTHORS files in distribution or http://mpg123.de initially written Oliver Fromme old timestamp: Wed Apr 9 20:57:47 MET DST 1997 Thomas' notes: I used to do GET http://server/path HTTP/1.0 But RFC 1945 says: The absoluteURI form is only allowed when the request is being made to a proxy. so I should not do that. Since name based virtual hosts need the hostname in the request, I still need to provide that info. Enter HTTP/1.1... there is a Host eader field to use (that mpg123 supposedly has used since some time anyway - but did it really work with my vhost test server)? Now GET /path/bla HTTP/1.1\r\nHost: host[:port] Should work, but as a funny sidenote: RFC2616: To allow for transition to absoluteURIs in all requests in future versions of HTTP, all HTTP/1.1 servers MUST accept the absoluteURI form in requests, even though HTTP/1.1 clients will only generate them in requests to proxies. I was already full-on HTTP/1.1 as I recognized that mpg123 then would have to accept the chunked transfer encoding. That is not desireable for its purpose... maybe when interleaving of shoutcasts with metadata chunks is supported, we can upgrade to 1.1. Funny aspect there is that shoutcast servers do not do HTTP/1.1 chunked transfer but implement some different chunking themselves...*/#include "config.h"#if !defined(WIN32) && !defined(GENERIC)#include <stdlib.h>#include <stdio.h>#include <string.h>/* for SIZE_MAX */#ifdef HAVE_STDINT_H#include <stdint.h>#endif#ifndef SIZE_MAX/* hm, is this portable across preprocessors? */#define SIZE_MAX ((size_t)-1)#endif#define HTTP_MAX_RELOCATIONS 20#include <netdb.h>#include <sys/param.h>#include <sys/types.h>#include <sys/socket.h>#include <netinet/in.h>#include <arpa/inet.h>#include <errno.h>#include <ctype.h>#include "config.h"#include "mpg123.h"#include "debug.h"#ifndef INADDR_NONE#define INADDR_NONE 0xffffffff#endifvoid 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; }}int readstring (char *string, int maxlen, FILE *f){#if 0 char *result;#endif int pos = 0; while(pos < maxlen) { if( read(fileno(f),string+pos,1) == 1) { pos++; if(string[pos-1] == '\n') { break; } } else if(errno != EINTR) { fprintf (stderr, "Error reading from socket or unexpected EOF.\n"); exit(1); } } string[pos] = 0; return pos;#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, size_t authlen){ char *pos; *auth = 0; if (!(strncmp(url, "http://", 7))) url += 7; if( (pos = strchr(url,'@')) ) { int i; for(i=0;i<pos-url;i++) { if( url[i] == '/' ) return 0; } if (pos-url >= authlen) { fprintf (stderr, "Error: authentication data exceeds max. length.\n"); return -1; } strncpy(auth,url,pos-url); auth[pos-url] = 0; memmove(url,pos+1,strlen(pos+1)+1); return 1; } return 0;}char *url2hostport (char *url, char **hname, unsigned long *hip, unsigned int *port){ char *cptr; struct hostent *myhostent; struct in_addr myaddr; int isip = 1; if (!(strncmp(url, "http://", 7))) url += 7; cptr = url; while (*cptr && *cptr != ':' && *cptr != '/') { if ((*cptr < '0' || *cptr > '9') && *cptr != '.') isip = 0; cptr++; } *hname = strdup(url); /* removed the strndup for better portability */ if (!(*hname)) { *hname = NULL; return (NULL); } (*hname)[cptr - url] = 0; if (!isip) { if (!(myhostent = gethostbyname(*hname))) return (NULL); memcpy (&myaddr, myhostent->h_addr, sizeof(myaddr)); *hip = myaddr.s_addr; } else if ((*hip = inet_addr(*hname)) == INADDR_NONE) return (NULL); if (!*cptr || *cptr == '/') { *port = 80; return (cptr); } *port = atoi(++cptr); if (*port > 65535) { /* Illegal port number. Ignore and use default. */ *port = 80; } while (*cptr && *cptr != '/') cptr++; return (cptr);}char *proxyurl = NULL;unsigned long proxyip = 0;unsigned int proxyport;/* That is not real ... I should really check the type of what I get! */#define ACCEPT_HEAD "Accept: audio/mpeg, audio/x-mpegurl, audio/x-scpls, */*\r\n"/* needed for HTTP/1.1 non-pipelining mode *//* #define CONN_HEAD "Connection: close\r\n" */#define CONN_HEAD ""char *httpauth = NULL;char *httpauth1 = NULL;int http_open (char* url, char** content_type){ /* TODO: make sure ulong vs. size_t is really clear! */ /* TODO: change this whole thing until I stop disliking it */ char *purl, *host, *request, *response, *sptr; char* request_url = NULL; size_t request_url_size = 0; size_t purl_size; size_t linelength, linelengthbase, tmp; unsigned long myip = 0; unsigned int myport = 0; int sock; int relocate, numrelocs = 0; struct sockaddr_in server; FILE *myfile; /* workaround for http://www.global24music.com/rautemusik/files/extreme/isdn.pls this site's apache gives me a relocation to the same place when I give the port in Host request field for the record: Apache/2.0.51 (Fedora) */ int try_without_port = 0; host = NULL; purl = NULL; request = NULL; response = 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 : ""); sock = -1; goto exit; } } else proxyip = INADDR_NONE; } /* The length of purl is upper bound by 3*strlen(url) + 1 if * everything in it is a space (%20) - or any encoded character */ if (strlen(url) >= SIZE_MAX/3) { fprintf (stderr, "URL too long. Skipping...\n"); sock = -1; goto exit; } /* +1 since we may want to add / if needed */ purl_size = strlen(url)*3 + 1 + 1; purl = (char *)malloc(purl_size); if (!purl) { fprintf (stderr, "malloc() failed, out of memory.\n"); exit (1); } /* make _sure_ that it is null-terminated */ purl[purl_size-1] = 0; /* * 2000-10-21: * We would like spaces to be automatically converted to %20's when * fetching via HTTP. * -- Martin Sj鰃ren <md9ms@mdstud.chalmers.se> * Hm, why only spaces? Maybe one should do this http stuff more properly... */ if ((sptr = strchr(url, ' ')) == NULL) { strcpy (purl, url); } else { char *urlptr = url; purl[0] = '\0'; do { strncat (purl, urlptr, sptr-urlptr); strcat (purl, "%20"); urlptr = sptr + 1; } while ((sptr = strchr (urlptr, ' ')) != NULL); strcat (purl, urlptr); } /* now see if a terminating / may be needed */ if(strchr(purl+(strncmp("http://", purl, 7) ? 0 : 7), '/') == NULL) strcat(purl, "/"); /* some paranoia */ if(httpauth1 != NULL) free(httpauth1); httpauth1 = (char *)malloc((strlen(purl) + 1)); if(!httpauth1) { fprintf(stderr, "malloc() failed, out of memory.\n"); exit(1); } if (getauthfromURL(purl,httpauth1,strlen(purl)) < 0) { sock = -1; goto exit; } /* "GET http://" 11 * " HTTP/1.0\r\nUser-Agent: <PACKAGE_NAME>/<PACKAGE_VERSION>\r\n" * 26 + PACKAGE_NAME + PACKAGE_VERSION * ACCEPT_HEAD strlen(ACCEPT_HEAD) * "Authorization: Basic \r\n" 23 * "\r\n" 2 */ linelengthbase = 62 + strlen(PACKAGE_NAME) + strlen(PACKAGE_VERSION) + strlen(ACCEPT_HEAD) + strlen(CONN_HEAD); if(httpauth) { tmp = (strlen(httpauth) + 1) * 4; if (strlen(httpauth) >= SIZE_MAX/4 - 1 || linelengthbase + tmp < linelengthbase) { fprintf(stderr, "HTTP authentication too long. Skipping...\n"); sock = -1; goto exit; } linelengthbase += tmp; } if(httpauth1) { tmp = (strlen(httpauth1) + 1) * 4; if (strlen(httpauth1) >= SIZE_MAX/4 - 1 || linelengthbase + tmp < linelengthbase) { fprintf(stderr, "HTTP authentication too long. Skipping...\n"); sock = -1; goto exit; } linelengthbase += tmp; } do { char* ttemp; /* save a full, valid url for later */ if(request_url_size < (strlen(purl) + 8))
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -