Hi,

You guys may be interested in a patch that I have developed to improve
HTTP streaming support. A little background, I run an Apache web server
at home with all my mp3s served using the Apache::MP3 module so I can
listen to my collection while I'm at work (see http://modperl.com:9000/Songs/
for an Apache::MP3 demo). In order to protect my files from unauthorised
use all accesses need to be authenticated with a user and password.
Unfortunately I could not find an mp3 player that could handle this, so
I bit the bullet and added the required support myself.

The patch itself consists of two parts:

The first part fixes a bug in EncodeURI() and adds user/password
authentication support when opening the stream, using the standard
http://user:password@host:port/file syntax.

The second part attempts to extract the track name and number from the
URL to display in the playlist before the stream is opened.

diff -NurdbX excl.txt freeamp.orig/io/http/httpinput.cpp freeamp/io/http/httpinput.cpp
--- freeamp.orig/io/http/httpinput.cpp  Tue Oct 16 06:58:12 2001
+++ freeamp/io/http/httpinput.cpp       Sat Apr 27 00:07:22 2002
@@ -467,8 +467,8 @@
       // Do not replace %## sequences -- they are already encoded and
       // ready to roll
       if (URI[convert] == '%' && URI.length() - convert > 2 &&
-          isdigit(URI[convert + 1]) && 
-          isdigit(URI[convert + 2])) 
+          isxdigit(URI[convert + 1]) && 
+          isxdigit(URI[convert + 2])) 
       {
           convert++;
           continue;
@@ -483,6 +483,131 @@
    }
 }
 
+
+static
+char *
+Base64Encode
+(   char                *strDest,
+    char                *strSrce
+)
+{   static const char   alphabet[] = 
+"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
+    char                *strSave   = strDest;
+    unsigned long       dwBits;
+    int                 nCount;
+
+    nCount = 0;
+    dwBits = 0;
+
+    while (*strSrce)
+    {
+        dwBits <<= 8;
+        dwBits |= (unsigned char) *strSrce++;
+
+        if (++nCount == 3)
+        {
+            *strDest++ = alphabet[(dwBits >> 18)       ];
+            *strDest++ = alphabet[(dwBits >> 12) & 0x3f];
+            *strDest++ = alphabet[(dwBits >>  6) & 0x3f];
+            *strDest++ = alphabet[(dwBits      ) & 0x3f];
+            dwBits = 0;
+            nCount = 0;
+        }
+    }
+
+    if (nCount)
+    {
+        dwBits <<= (nCount == 1) ? 16 : 8;
+
+        *strDest++ = alphabet[(dwBits >> 18)       ];
+        *strDest++ = alphabet[(dwBits >> 12) & 0x3f];
+
+        if (nCount == 1)
+        {
+            *strDest++ = '=';
+        }
+        else
+        {
+            *strDest++ = alphabet[(dwBits >> 6) & 0x3f];
+        }
+
+        *strDest++ = '=';
+    }
+
+    *strDest = '\0';
+
+    return strSave;
+}
+
+
+static
+char *
+ParseURI
+(   char        *szURI,
+    char        *szHostName,
+    char        *szAuth,
+    unsigned    *puiPort
+)
+{
+    // Ignore leading white space
+    while (*szURI && *szURI <= ' ')
+        szURI++;
+
+    if (strncasecmp(szURI, "http://";, 7))
+        return NULL;
+
+    szURI += 7;
+
+    // No user name and password by default
+    szAuth[0] = '\0';
+
+    // Find start of file name
+    char *szFile = strchr(szURI, '/');
+
+    // If no file name
+    if (szFile == NULL)
+    {
+        szFile = strchr(szURI, '?');
+        if (szFile == NULL)
+        {
+            // Point to end of URI where file name should go
+            szFile = szURI + strlen(szURI);
+        }
+    }
+
+    // Find end of user name and password
+    char *at = strchr(szURI, '@');
+
+    if (at)
+    {
+        // If '@' not part of file name
+        if (szFile > at)
+        {
+            // Temporarily truncate at '@'
+            *at = '\0';
+
+            // Return username and password base64 encoded
+            Base64Encode(szAuth, szURI);
+
+            // Restore
+            *at = '@';
+
+            // Skip username and password
+            szURI = at + 1;
+        }
+    }
+
+    int nArgs = sscanf(szURI, "%[^:/?]:%u", szHostName, puiPort);
+
+    if (nArgs < 1)
+        return NULL;
+
+    if (nArgs == 1)
+        *puiPort = iHttpPort;
+
+    return szFile;
+}
+
+
 Error
 HttpInput::Open(void)
 {
@@ -501,30 +626,28 @@
    bool      bUseTitleStreaming = true, bUseAltNIC = false;
    int       iHeaderBytes = 0, iCurHeaderSize = 1024;
    string    file;
+   char     szAuth[128];
 
    szStreamName = NULL;
    szStreamUrl = NULL;
    if (!m_bUseProxy)
    {
-      const char* ptr;
-
-      iRet = sscanf(m_path, " http://%[^:/]:%d";, szHostName, &iPort);
-      if (iRet < 1)
+         pPtr = ParseURI(m_path, szHostName, szAuth, &iPort);
+         if (pPtr == NULL)
       {
-         ReportError("Bad URL format. URL format: http://<host name>"
+         ReportError("Bad URL format. URL format: http://[user:pass@;]<host name>"
                      ":[port][/path]. Please check the URL and try again.");
          return (Error) httpError_BadUrl;
       }
-      ptr = strchr(m_path + 7, '/');
-      file = (ptr ? ptr : "");
+         file = pPtr;
    }
    else
    {
-      iRet = sscanf(m_szProxyHost, " http://%[^:/]:%d";, szHostName, &iPort);
-      if (iRet < 1)
+         pPtr = ParseURI(m_szProxyHost, szHostName, szAuth, &iPort);
+         if ((pPtr == NULL) || (pPtr[0] == '/' && pPtr[1] != '\0'))
       {
          ReportError("Bad Proxy URL format. URL format: http:"
-                     "//<host name>:[port]. Please check your proxy settings "
+                     "//[user:pass@]<host name>:[port]. Please check your proxy 
+settings "
                      "in the Options.");
 
          m_pContext->log->Error("Debug: m_szProxyHost: '%s'\n", m_szProxyHost);
@@ -534,9 +657,6 @@
    }
    EncodeURI(file);
 
-   if (iRet < 2)
-      iPort = iHttpPort;
-
    memset(&sAddr, 0, sizeof(struct sockaddr_in));
 
    ReportStatus("Looking up host %s...", szHostName);
@@ -675,6 +795,11 @@
               "Icy-MetaData:1\r\n"
               "User-Agent: FreeAmp/%s\r\n", szHostName, FREEAMP_VERSION);
    }
+   if (szAuth[0])
+   {
+          sprintf(szQuery + strlen(szQuery),
+              "Authorization: basic %s\r\n", szAuth);
+   }
 
    m_pContext->prefs->GetPrefBoolean(kUseTitleStreamingPref,
                                      &bUseTitleStreaming);
diff -NurdbX excl.txt freeamp.orig/plm/metadata/misc/misc.cpp 
freeamp/plm/metadata/misc/misc.cpp
--- freeamp.orig/plm/metadata/misc/misc.cpp     Wed Feb 21 03:19:08 2001
+++ freeamp/plm/metadata/misc/misc.cpp  Sat Apr 27 01:05:21 2002
@@ -173,7 +173,103 @@
     }
     else if(!strncasecmp(url, "http://";, 7) && !metadata->Title().size())
     {
-        metadata->SetTitle("HTTP Stream");
+//      metadata->SetTitle("HTTP Stream");
+
+        // Get working copy of URL
+        char *urlCopy = new char[strlen(url) + 1];
+        strcpy(urlCopy, url);
+
+        // Find start of file name
+        char *fileName = strrchr(urlCopy, '/');
+        if (fileName == NULL)
+            fileName = urlCopy;
+        else
+            fileName++;
+
+        // Remove query
+        char *ext = strrchr(fileName, '?');
+        if (ext) {
+            *ext = '\0';
+        }
+
+        // Undo URL escape sequences
+        char *cleanName = new char[strlen(fileName) + 1];
+        char *p         = cleanName;
+        char *f         = fileName;
+        while (*f)
+        {
+            if (f[0] == '%' && isxdigit(f[1]) && isxdigit(f[2]))
+            {
+                unsigned char n;
+                n   = ((isdigit(f[1]) ? (f[1] - '0') : (toupper(f[1]) -'A' + 10)) * 
+16)
+                    |  (isdigit(f[2]) ? (f[2] - '0') : (toupper(f[2]) -'A' + 10));
+                if (n) *p = n;
+                f += 3;
+            }
+            else 
+            {
+                *p = *f++;
+            }
+            p++;
+        }
+        *p = '\0';
+
+        // Remove extension
+        ext = strrchr(cleanName, '.');
+        if (ext) {
+            *ext = '\0';
+        }
+
+        // Bingo!
+        metadata->SetTitle(*cleanName ? cleanName : url);
+
+        // Try to find a track number i.e. a decimal number between
+        // 1 and 99 surrounded by non alpha characters
+        if (*cleanName)
+        {
+            p = cleanName;
+            while (*p)
+            {
+                // Skip non numerics
+                while (!isdigit(*p))
+                    p++;
+
+                // Ensure character before digit is not alphabetic
+                if (p != fileName && isalpha(p[-1]))
+                {
+                    // Skip digits
+                    while (isdigit(*p))
+                        p++;
+
+                    // Try again
+                    continue;
+                }
+
+                // Evaluate digits
+                int n = 0;
+                while (isdigit(*p))
+                {
+                    n *= 10;
+                    n += *p++ - '0';
+                }
+
+                // Ensure following character is not alphabetic
+                if (isalpha(*p))
+                    continue;
+
+                // Must be in range of 1 to 99
+                if (n > 0 && n < 100)
+                {
+                    // Got it
+                    metadata->SetTrack(n);
+                    break;
+                }
+            }
+        }
+
+        // Clean up
+        delete [] cleanName;
+        delete [] urlCopy;
     }
     else if(!strncasecmp(url, "rtp://", 6) && !metadata->Title().size())
     {


Nick

----------------------------------------------------------------
Nick Holgate <[EMAIL PROTECTED]>
GPG key available from public key servers : Key ID FD9C18AF
Fingerprint = 9DCA EDEA D5C5 57DA 23F3  1A2B 2273 5645 FD9C 18AF

_______________________________________________
[EMAIL PROTECTED]
http://www.freeamp.org/mailman/listinfo/freeamp-dev

Reply via email to