]> git.sesse.net Git - vlc/blobdiff - modules/control/http/util.c
backport of [13300]
[vlc] / modules / control / http / util.c
index d9c7ba238de081a765b8c12edb71745600307f43..56ca0d5677b873aeec91a367b05269e384fb274d 100644 (file)
@@ -60,9 +60,7 @@ char *E_(FileToUrl)( char *name, vlc_bool_t *pb_index )
     while( *name )
     {
         if( *name == '\\' )
-        {
-            *p++ = '/';
-        }
+            *name = '/';
         name++;
     }
 #endif
@@ -103,7 +101,7 @@ int E_(FileLoad)( FILE *f, char **pp_data, int *pi_data )
 
 /* Parse a directory and recursively add files */
 int E_(ParseDirectory)( intf_thread_t *p_intf, char *psz_root,
-                           char *psz_dir )
+                        char *psz_dir )
 {
     intf_sys_t     *p_sys = p_intf->p_sys;
     char           dir[MAX_DIR_SIZE];
@@ -120,6 +118,14 @@ int E_(ParseDirectory)( intf_thread_t *p_intf, char *psz_root,
 
     int           i_dirlen;
 
+    char sep;
+
+#if defined( WIN32 )
+    sep = '\\';
+#else
+    sep = '/';
+#endif
+
 #ifdef HAVE_SYS_STAT_H
     if( stat( psz_dir, &stat_info ) == -1 || !S_ISDIR( stat_info.st_mode ) )
     {
@@ -142,7 +148,7 @@ int E_(ParseDirectory)( intf_thread_t *p_intf, char *psz_root,
 
     msg_Dbg( p_intf, "dir=%s", psz_dir );
 
-    sprintf( dir, "%s/.access", psz_dir );
+    sprintf( dir, "%s%c.access", psz_dir, sep );
     if( ( file = fopen( dir, "r" ) ) != NULL )
     {
         char line[1024];
@@ -176,7 +182,7 @@ int E_(ParseDirectory)( intf_thread_t *p_intf, char *psz_root,
         fclose( file );
     }
 
-    sprintf( dir, "%s/.hosts", psz_dir );
+    sprintf( dir, "%s%c.hosts", psz_dir, sep );
     p_acl = ACL_Create( p_intf, VLC_FALSE );
     if( ACL_LoadFile( p_acl, dir ) )
     {
@@ -196,24 +202,49 @@ int E_(ParseDirectory)( intf_thread_t *p_intf, char *psz_root,
          || ( i_dirlen + strlen( p_dir_content->d_name ) > MAX_DIR_SIZE ) )
             continue;
 
-        sprintf( dir, "%s/%s", psz_dir, p_dir_content->d_name );
+        sprintf( dir, "%s%c%s", psz_dir, sep, p_dir_content->d_name );
         if( E_(ParseDirectory)( p_intf, psz_root, dir ) )
         {
-            httpd_file_sys_t *f = malloc( sizeof( httpd_file_sys_t ) );
+            httpd_file_sys_t *f = NULL;
+            httpd_handler_sys_t *h = NULL;
             vlc_bool_t b_index;
-            char *psz_tmp;
+            char *psz_tmp, *psz_file, *psz_name, *psz_ext;
 
-            f->p_intf  = p_intf;
-            f->p_file = NULL;
-            f->p_redir = NULL;
-            f->p_redir2 = NULL;
             psz_tmp = vlc_fix_readdir_charset( p_intf, dir );
-            f->file = E_(FromUTF8)( p_intf, psz_tmp );
+            psz_file = E_(FromUTF8)( p_intf, psz_tmp );
             free( psz_tmp );
             psz_tmp = vlc_fix_readdir_charset( p_intf,
                                                &dir[strlen( psz_root )] );
-            f->name = E_(FileToUrl)( psz_tmp, &b_index );
+            psz_name = E_(FileToUrl)( psz_tmp, &b_index );
             free( psz_tmp );
+            psz_ext = strrchr( psz_file, '.' );
+            if( psz_ext != NULL )
+            {
+                int i;
+                psz_ext++;
+                for( i = 0; i < p_sys->i_handlers; i++ )
+                    if( !strcmp( p_sys->pp_handlers[i]->psz_ext, psz_ext ) )
+                        break;
+                if( i < p_sys->i_handlers )
+                {
+                    f = malloc( sizeof( httpd_handler_sys_t ) );
+                    h = (httpd_handler_sys_t *)f;
+                    f->b_handler = VLC_TRUE;
+                    h->p_association = p_sys->pp_handlers[i];
+                }
+            }
+            if( f == NULL )
+            {
+                f = malloc( sizeof( httpd_file_sys_t ) );
+                f->b_handler = VLC_FALSE;
+            }
+
+            f->p_intf  = p_intf;
+            f->p_file = NULL;
+            f->p_redir = NULL;
+            f->p_redir2 = NULL;
+            f->file = psz_file;
+            f->name = psz_name;
             f->b_html = strstr( &dir[strlen( psz_root )], ".htm" ) ? VLC_TRUE : VLC_FALSE;
 
             if( !f->name )
@@ -226,16 +257,32 @@ int E_(ParseDirectory)( intf_thread_t *p_intf, char *psz_root,
             msg_Dbg( p_intf, "file=%s (url=%s)",
                      f->file, f->name );
 
-            f->p_file = httpd_FileNew( p_sys->p_httpd_host,
-                                       f->name,
-                                       f->b_html ? p_sys->psz_html_type : NULL,
-                                       user, password, p_acl,
-                                       E_(HttpCallback), f );
-
-            if( f->p_file )
+            if( !f->b_handler )
+            {
+                f->p_file = httpd_FileNew( p_sys->p_httpd_host,
+                                           f->name,
+                                           f->b_html ? p_sys->psz_html_type :
+                                            NULL,
+                                           user, password, p_acl,
+                                           E_(HttpCallback), f );
+                if( f->p_file != NULL )
+                {
+                    TAB_APPEND( p_sys->i_files, p_sys->pp_files, f );
+                }
+            }
+            else
             {
-                TAB_APPEND( p_sys->i_files, p_sys->pp_files, f );
+                h->p_handler = httpd_HandlerNew( p_sys->p_httpd_host,
+                                                 f->name,
+                                                 user, password, p_acl,
+                                                 E_(HandlerCallback), h );
+                if( h->p_handler != NULL )
+                {
+                    TAB_APPEND( p_sys->i_files, p_sys->pp_files,
+                                (httpd_file_sys_t *)h );
+                }
             }
+
             /* for url that ends by / add
              *  - a redirect from rep to rep/
              *  - in case of index.* rep/index.html to rep/ */
@@ -288,14 +335,36 @@ char *E_(FromUTF8)( intf_thread_t *p_intf, char *psz_utf8 )
 
     if ( p_sys->iconv_from_utf8 != (vlc_iconv_t)-1 )
     {
-        char *psz_in = psz_utf8;
-        size_t i_in = strlen(psz_in);
+        size_t i_in = strlen(psz_utf8);
         size_t i_out = i_in * 2;
         char *psz_local = malloc(i_out + 1);
         char *psz_out = psz_local;
+        size_t i_ret;
+        char psz_tmp[i_in + 1];
+        char *psz_in = psz_tmp;
+        uint8_t *p = (uint8_t *)psz_tmp;
+        strcpy( psz_tmp, psz_utf8 );
+
+        /* Fix Unicode quotes. If we are here we are probably converting
+         * to an inferior charset not understanding Unicode quotes. */
+        while( *p )
+        {
+            if( p[0] == 0xe2 && p[1] == 0x80 && p[2] == 0x99 )
+            {
+                *p = '\'';
+                memmove( &p[1], &p[3], strlen(&p[3]) + 1 );
+            }
+            if( p[0] == 0xe2 && p[1] == 0x80 && p[2] == 0x9a )
+            {
+                *p = '"';
+                memmove( &p[1], &p[3], strlen(&p[3]) + 1 );
+            }
+            p++;
+        }
+        i_in = strlen( psz_tmp );
 
-        size_t i_ret = vlc_iconv( p_sys->iconv_from_utf8, &psz_in, &i_in,
-                                  &psz_out, &i_out );
+        i_ret = vlc_iconv( p_sys->iconv_from_utf8, &psz_in, &i_in,
+                           &psz_out, &i_out );
         if( i_ret == (size_t)-1 || i_in )
         {
             msg_Warn( p_intf,
@@ -355,55 +424,55 @@ void E_(PlaylistListNode)( intf_thread_t *p_intf, playlist_t *p_pl,
         {
             char value[512];
             char *psz;
-            mvar_t *itm = mvar_New( name, "set" );
+            mvar_t *itm = E_(mvar_New)( name, "set" );
 
             sprintf( value, "%d", ( p_pl->status.p_item == p_node )? 1 : 0 );
-            mvar_AppendNewVar( itm, "current", value );
+            E_(mvar_AppendNewVar)( itm, "current", value );
 
             sprintf( value, "%d", p_node->input.i_id );
-            mvar_AppendNewVar( itm, "index", value );
+            E_(mvar_AppendNewVar)( itm, "index", value );
 
             psz = E_(FromUTF8)( p_intf, p_node->input.psz_name );
-            mvar_AppendNewVar( itm, "name", psz );
+            E_(mvar_AppendNewVar)( itm, "name", psz );
             free( psz );
 
             psz = E_(FromUTF8)( p_intf, p_node->input.psz_uri );
-            mvar_AppendNewVar( itm, "uri", psz );
+            E_(mvar_AppendNewVar)( itm, "uri", psz );
             free( psz );
 
             sprintf( value, "Item");
-            mvar_AppendNewVar( itm, "type", value );
+            E_(mvar_AppendNewVar)( itm, "type", value );
 
             sprintf( value, "%d", i_depth );
-            mvar_AppendNewVar( itm, "depth", value );
+            E_(mvar_AppendNewVar)( itm, "depth", value );
 
-            mvar_AppendVar( s, itm );
+            E_(mvar_AppendVar)( s, itm );
         }
         else
         {
             char value[512];
             char *psz;
             int i_child;
-            mvar_t *itm = mvar_New( name, "set" );
+            mvar_t *itm = E_(mvar_New)( name, "set" );
 
             psz = E_(FromUTF8)( p_intf, p_node->input.psz_name );
-            mvar_AppendNewVar( itm, "name", psz );
-            mvar_AppendNewVar( itm, "uri", psz );
+            E_(mvar_AppendNewVar)( itm, "name", psz );
+            E_(mvar_AppendNewVar)( itm, "uri", psz );
             free( psz );
 
             sprintf( value, "Node" );
-            mvar_AppendNewVar( itm, "type", value );
+            E_(mvar_AppendNewVar)( itm, "type", value );
 
             sprintf( value, "%d", p_node->input.i_id );
-            mvar_AppendNewVar( itm, "index", value );
+            E_(mvar_AppendNewVar)( itm, "index", value );
 
             sprintf( value, "%d", p_node->i_children);
-            mvar_AppendNewVar( itm, "i_children", value );
+            E_(mvar_AppendNewVar)( itm, "i_children", value );
 
             sprintf( value, "%d", i_depth );
-            mvar_AppendNewVar( itm, "depth", value );
+            E_(mvar_AppendNewVar)( itm, "depth", value );
 
-            mvar_AppendVar( s, itm );
+            E_(mvar_AppendVar)( s, itm );
 
             for (i_child = 0 ; i_child < p_node->i_children ; i_child++)
                 E_(PlaylistListNode)( p_intf, p_pl,
@@ -417,8 +486,7 @@ void E_(PlaylistListNode)( intf_thread_t *p_intf, playlist_t *p_pl,
 /****************************************************************************
  * Seek command parsing handling
  ****************************************************************************/
-
-void E_(Seek)( intf_thread_t *p_intf, char *p_value )
+void E_(HandleSeek)( intf_thread_t *p_intf, char *p_value )
 {
     intf_sys_t     *p_sys = p_intf->p_sys;
     vlc_value_t val;
@@ -600,7 +668,7 @@ void E_(Seek)( intf_thread_t *p_intf, char *p_value )
 /****************************************************************************
  * URI Parsing functions
  ****************************************************************************/
-int E_(uri_test_param)( char *psz_uri, const char *psz_name )
+int E_(TestURIParam)( char *psz_uri, const char *psz_name )
 {
     char *p = psz_uri;
 
@@ -617,7 +685,7 @@ int E_(uri_test_param)( char *psz_uri, const char *psz_name )
 
     return VLC_FALSE;
 }
-char *E_(uri_extract_value)( char *psz_uri, const char *psz_name,
+char *E_(ExtractURIValue)( char *psz_uri, const char *psz_name,
                              char *psz_value, int i_value_max )
 {
     char *p = psz_uri;
@@ -675,7 +743,7 @@ char *E_(uri_extract_value)( char *psz_uri, const char *psz_name,
     return p;
 }
 
-void E_(uri_decode_url_encoded)( char *psz )
+void E_(DecodeEncodedURI)( char *psz )
 {
     char *dup = strdup( psz );
     char *p = dup;
@@ -750,47 +818,295 @@ char *E_(FirstWord)( char *psz, char *new )
     else
         return NULL;
 }
+/**********************************************************************
+ * Find_end_MRL: Find the end of the sentence :
+ * this function parses the string psz and find the end of the item
+ * and/or option with detecting the " and ' problems.
+ * returns NULL if an error is detected, otherwise, returns a pointer
+ * of the end of the sentence (after the last character)
+**********************************************************************/
+static char *Find_end_MRL( char *psz )
+{
+    char *s_sent = psz;
+
+    switch( *s_sent )
+    {
+        case '\"':
+        {
+            s_sent++;
+
+            while( ( *s_sent != '\"' ) && ( *s_sent != '\0' ) )
+            {
+                if( *s_sent == '\'' )
+                {
+                    s_sent = Find_end_MRL( s_sent );
+
+                    if( s_sent == NULL )
+                    {
+                        return NULL;
+                    }
+                } else
+                {
+                    s_sent++;
+                }
+            }
+
+            if( *s_sent == '\"' )
+            {
+                s_sent++;
+                return s_sent;
+            } else  /* *s_sent == '\0' , which means the number of " is incorrect */
+            {
+                return NULL;
+            }
+            break;
+        }
+        case '\'':
+        {
+            s_sent++;
 
+            while( ( *s_sent != '\'' ) && ( *s_sent != '\0' ) )
+            {
+                if( *s_sent == '\"' )
+                {
+                    s_sent = Find_end_MRL( s_sent );
+
+                    if( s_sent == NULL )
+                    {
+                        return NULL;
+                    }
+                } else
+                {
+                    s_sent++;
+                }
+            }
+
+            if( *s_sent == '\'' )
+            {
+                s_sent++;
+                return s_sent;
+            } else  /* *s_sent == '\0' , which means the number of ' is incorrect */
+            {
+                return NULL;
+            }
+            break;
+        }
+        default: /* now we can look for spaces */
+        {
+            while( ( *s_sent != ' ' ) && ( *s_sent != '\0' ) )
+            {
+                if( ( *s_sent == '\'' ) || ( *s_sent == '\"' ) )
+                {
+                    s_sent = Find_end_MRL( s_sent );
+                } else
+                {
+                    s_sent++;
+                }
+            }
+            return s_sent;
+        }
+    }
+}
 /**********************************************************************
  * parse_MRL: parse the MRL, find the mrl string and the options,
  * create an item with all information in it, and return the item.
  * return NULL if there is an error.
  **********************************************************************/
-playlist_item_t *E_(parse_MRL)( intf_thread_t *p_intf, char *_psz,
+playlist_item_t *E_(MRLParse)( intf_thread_t *p_intf, char *psz,
                                    char *psz_name )
 {
-    char *psz = strdup( _psz );
+    char **ppsz_options = NULL;
+    char *mrl;
     char *s_mrl = psz;
+    int i_error = 0;
     char *s_temp;
+    int i = 0;
+    int i_options = 0;
     playlist_item_t * p_item = NULL;
 
+    /* In case there is spaces before the mrl */
+    while( ( *s_mrl == ' ' ) && ( *s_mrl != '\0' ) )
+    {
+        s_mrl++;
+    }
+
     /* extract the mrl */
-    s_temp = E_(FirstWord)( s_mrl, s_mrl );
+    s_temp = strstr( s_mrl , " :" );
     if( s_temp == NULL )
     {
         s_temp = s_mrl + strlen( s_mrl );
+    } else
+    {
+        while( (*s_temp == ' ') && (s_temp != s_mrl ) )
+        {
+            s_temp--;
+        }
+        s_temp++;
+    }
+
+    /* if the mrl is between " or ', we must remove them */
+    if( (*s_mrl == '\'') || (*s_mrl == '\"') )
+    {
+        mrl = (char *)malloc( (s_temp - s_mrl - 1) * sizeof( char ) );
+        strncpy( mrl , (s_mrl + 1) , s_temp - s_mrl - 2 );
+        mrl[ s_temp - s_mrl - 2 ] = '\0';
+    } else
+    {
+        mrl = (char *)malloc( (s_temp - s_mrl + 1) * sizeof( char ) );
+        strncpy( mrl , s_mrl , s_temp - s_mrl );
+        mrl[ s_temp - s_mrl ] = '\0';
     }
 
-    p_item = playlist_ItemNew( p_intf, s_mrl, psz_name );
     s_mrl = s_temp;
 
     /* now we can take care of the options */
-    while( *s_mrl != '\0' )
+    while( (*s_mrl != '\0') && (i_error == 0) )
     {
-        s_temp = E_(FirstWord)( s_mrl, s_mrl );
-        if( s_mrl == '\0' )
-            break;
-        if( s_temp == NULL )
+        switch( *s_mrl )
         {
-            s_temp = s_mrl + strlen( s_mrl );
+            case ' ':
+            {
+                s_mrl++;
+                break;
+            }
+            case ':': /* an option */
+            {
+                s_temp = Find_end_MRL( s_mrl );
+
+                if( s_temp == NULL )
+                {
+                    i_error = 1;
+                }
+                else
+                {
+                    i_options++;
+                    ppsz_options = realloc( ppsz_options , i_options *
+                                            sizeof(char *) );
+                    ppsz_options[ i_options - 1 ] =
+                        malloc( (s_temp - s_mrl + 1) * sizeof(char) );
+
+                    strncpy( ppsz_options[ i_options - 1 ] , s_mrl ,
+                             s_temp - s_mrl );
+
+                    /* don't forget to finish the string with a '\0' */
+                    (ppsz_options[ i_options - 1 ])[ s_temp - s_mrl ] = '\0';
+
+                    s_mrl = s_temp;
+                }
+                break;
+            }
+            default:
+            {
+                i_error = 1;
+                break;
+            }
+        }
+    }
+
+    if( i_error != 0 )
+    {
+        free( mrl );
+    }
+    else
+    {
+        /* now create an item */
+        p_item = playlist_ItemNew( p_intf, mrl, psz_name );
+        for( i = 0 ; i< i_options ; i++ )
+        {
+            playlist_ItemAddOption( p_item, ppsz_options[i] );
         }
-        if( *s_mrl != ':' )
-            msg_Warn( p_intf, "invalid MRL option: %s", s_mrl );
-        else
-            playlist_ItemAddOption( p_item, s_mrl );
-        s_mrl = s_temp;
     }
 
-    free( psz );
+    for( i = 0; i < i_options; i++ ) free( ppsz_options[i] );
+    if( i_options ) free( ppsz_options );
+
     return p_item;
 }
+/**********************************************************************
+ * RealPath: parse ../, ~ and path stuff
+ **********************************************************************/
+char *E_(RealPath)( intf_thread_t *p_intf, const char *psz_src )
+{
+    char *psz_dir;
+    char *p;
+    int i_len = strlen(psz_src);
+    char sep;
+
+#if defined( WIN32 )
+    sep = '\\';
+#else
+    sep = '/';
+#endif
+
+    psz_dir = malloc( i_len + 2 );
+    strcpy( psz_dir, psz_src );
+
+    /* Add a trailing sep to ease the .. step */
+    psz_dir[i_len] = sep;
+    psz_dir[i_len + 1] = '\0';
+
+#ifdef WIN32
+    /* Convert all / to native separator */
+    p = psz_dir;
+    while( (p = strchr( p, '/' )) != NULL )
+    {
+        *p = sep;
+    }
+#endif
+
+    /* Remove multiple separators and /./ */
+    p = psz_dir;
+    while( (p = strchr( p, sep )) != NULL )
+    {
+        if( p[1] == sep )
+            memmove( &p[1], &p[2], strlen(&p[2]) + 1 );
+        else if( p[1] == '.' && p[2] == sep )
+            memmove( &p[1], &p[3], strlen(&p[3]) + 1 );
+        else
+            p++;
+    }
+
+    if( psz_dir[0] == '~' )
+    {
+        char *dir = malloc( strlen(psz_dir)
+                             + strlen(p_intf->p_vlc->psz_userdir) );
+        /* This is incomplete : we should also support the ~cmassiot/ syntax. */
+        sprintf( dir, "%s%s", p_intf->p_vlc->psz_userdir, psz_dir + 1 );
+        free( psz_dir );
+        psz_dir = dir;
+    }
+
+    if( strlen(psz_dir) > 2 )
+    {
+        /* Fix all .. dir */
+        p = psz_dir + 3;
+        while( (p = strchr( p, sep )) != NULL )
+        {
+            if( p[-1] == '.' && p[-2] == '.' && p[-3] == sep )
+            {
+                char *q;
+                p[-3] = '\0';
+                if( (q = strrchr( psz_dir, sep )) != NULL )
+                {
+                    memmove( q + 1, p + 1, strlen(p + 1) + 1 );
+                    p = q + 1;
+                }
+                else
+                {
+                    memmove( psz_dir, p, strlen(p) + 1 );
+                    p = psz_dir + 3;
+                }
+            }
+            else
+                p++;
+        }
+    }
+
+    /* Remove trailing sep if there are at least 2 sep in the string
+     * (handles the C:\ stuff) */
+    p = strrchr( psz_dir, sep );
+    if( p != NULL && p[1] == '\0' && p != strchr( psz_dir, sep ) )
+        *p = '\0';
+
+    return psz_dir;
+}