static int vlclua_httpd_file_new( lua_State *L ) { httpd_host_t **pp_host = (httpd_host_t **)luaL_checkudata( L, 1, "httpd_host" ); const char *psz_url = luaL_checkstring( L, 2 ); const char *psz_mime = luaL_nilorcheckstring( L, 3 ); const char *psz_user = luaL_nilorcheckstring( L, 4 ); const char *psz_password = luaL_nilorcheckstring( L, 5 ); const vlc_acl_t **pp_acl = lua_isnil( L, 6 ) ? NULL : luaL_checkudata( L, 6, "acl" ); /* Stack item 7 is the callback function */ luaL_argcheck( L, lua_isfunction( L, 7 ), 7, "Should be a function" ); /* Stack item 8 is the callback data */ httpd_file_sys_t *p_sys = (httpd_file_sys_t *) malloc( sizeof( httpd_file_sys_t ) ); if( !p_sys ) return luaL_error( L, "Failed to allocate private buffer." ); p_sys->L = lua_newthread( L ); p_sys->ref = luaL_ref( L, LUA_REGISTRYINDEX ); /* pops the object too */ lua_xmove( L, p_sys->L, 2 ); httpd_file_t *p_file = httpd_FileNew( *pp_host, psz_url, psz_mime, psz_user, psz_password, pp_acl?*pp_acl:NULL, vlclua_httpd_file_callback, p_sys ); if( !p_file ) { free( p_sys ); return luaL_error( L, "Failed to create HTTPd file." ); } httpd_file_t **pp_file = lua_newuserdata( L, sizeof( httpd_file_t * ) ); *pp_file = p_file; if( luaL_newmetatable( L, "httpd_file" ) ) { lua_pushcfunction( L, vlclua_httpd_file_delete ); lua_setfield( L, -2, "__gc" ); } lua_setmetatable( L, -2 ); return 1; }
/***************************************************************************** * HTTPOpen: Start the internal HTTP server *****************************************************************************/ int E_(HTTPOpen)( access_t *p_access ) { #define FREE( x ) \ if ( (x) != NULL ) \ free( x ); access_sys_t *p_sys = p_access->p_sys; char *psz_address, *psz_cert = NULL, *psz_key = NULL, *psz_ca = NULL, *psz_crl = NULL, *psz_user = NULL, *psz_password = NULL, *psz_acl = NULL; int i_port = 0; char psz_tmp[10]; vlc_acl_t *p_acl = NULL; httpd_file_sys_t *f; vlc_mutex_init( p_access, &p_sys->httpd_mutex ); vlc_cond_init( p_access, &p_sys->httpd_cond ); p_sys->b_request_frontend_info = p_sys->b_request_mmi_info = VLC_FALSE; p_sys->i_httpd_timeout = 0; psz_address = var_GetString( p_access, "dvb-http-host" ); if( psz_address != NULL && *psz_address ) { char *psz_parser = strchr( psz_address, ':' ); if( psz_parser ) { *psz_parser++ = '\0'; i_port = atoi( psz_parser ); } } else { if ( psz_address != NULL ) free( psz_address ); return VLC_SUCCESS; } /* determine SSL configuration */ psz_cert = var_GetString( p_access, "dvb-http-intf-cert" ); if ( psz_cert != NULL && *psz_cert ) { msg_Dbg( p_access, "enabling TLS for HTTP interface (cert file: %s)", psz_cert ); psz_key = config_GetPsz( p_access, "dvb-http-intf-key" ); psz_ca = config_GetPsz( p_access, "dvb-http-intf-ca" ); psz_crl = config_GetPsz( p_access, "dvb-http-intf-crl" ); if ( i_port <= 0 ) i_port = 8443; } else { if ( !*psz_cert ) { free( psz_cert ); psz_cert = NULL; } if ( i_port <= 0 ) i_port= 8082; } /* Ugly hack to allow to run several HTTP servers on different ports. */ sprintf( psz_tmp, ":%d", i_port + 1 ); config_PutPsz( p_access, "dvb-http-host", psz_tmp ); msg_Dbg( p_access, "base %s:%d", psz_address, i_port ); p_sys->p_httpd_host = httpd_TLSHostNew( VLC_OBJECT(p_access), psz_address, i_port, psz_cert, psz_key, psz_ca, psz_crl ); FREE( psz_cert ); FREE( psz_key ); FREE( psz_ca ); FREE( psz_crl ); if ( p_sys->p_httpd_host == NULL ) { msg_Err( p_access, "cannot listen on %s:%d", psz_address, i_port ); free( psz_address ); return VLC_EGENERIC; } free( psz_address ); psz_user = var_GetString( p_access, "dvb-http-user" ); psz_password = var_GetString( p_access, "dvb-http-password" ); psz_acl = var_GetString( p_access, "dvb-http-acl" ); if ( psz_acl != NULL ) { p_acl = ACL_Create( p_access, VLC_FALSE ); if( ACL_LoadFile( p_acl, psz_acl ) ) { ACL_Destroy( p_acl ); p_acl = NULL; } } /* Declare an index.html file. */ f = malloc( sizeof(httpd_file_sys_t) ); f->p_access = p_access; f->p_file = httpd_FileNew( p_sys->p_httpd_host, "/index.html", "text/html; charset=UTF-8", psz_user, psz_password, p_acl, HttpCallback, f ); FREE( psz_user ); FREE( psz_password ); FREE( psz_acl ); if ( p_acl != NULL ) ACL_Destroy( p_acl ); if ( f->p_file == NULL ) { free( f ); p_sys->p_httpd_file = NULL; return VLC_EGENERIC; } p_sys->p_httpd_file = f; p_sys->p_httpd_redir = httpd_RedirectNew( p_sys->p_httpd_host, "/index.html", "/" ); #undef FREE return VLC_SUCCESS; }
/* Parse a directory and recursively add files */ int ParseDirectory( intf_thread_t *p_intf, char *psz_root, char *psz_dir ) { intf_sys_t *p_sys = p_intf->p_sys; char dir[MAX_DIR_SIZE]; DIR *p_dir; vlc_acl_t *p_acl; FILE *file; char *user = NULL; char *password = NULL; int i_dirlen; if( ( p_dir = utf8_opendir( psz_dir ) ) == NULL ) { if( errno != ENOENT && errno != ENOTDIR ) msg_Err( p_intf, "cannot open directory (%s)", psz_dir ); return VLC_EGENERIC; } i_dirlen = strlen( psz_dir ); if( i_dirlen + 10 > MAX_DIR_SIZE ) { msg_Warn( p_intf, "skipping too deep directory (%s)", psz_dir ); closedir( p_dir ); return 0; } msg_Dbg( p_intf, "dir=%s", psz_dir ); snprintf( dir, sizeof( dir ), "%s"DIR_SEP".access", psz_dir ); if( ( file = utf8_fopen( dir, "r" ) ) != NULL ) { char line[1024]; int i_size; msg_Dbg( p_intf, "find .access in dir=%s", psz_dir ); i_size = fread( line, 1, 1023, file ); if( i_size > 0 ) { char *p; while( i_size > 0 && ( line[i_size-1] == '\n' || line[i_size-1] == '\r' ) ) { i_size--; } line[i_size] = '\0'; p = strchr( line, ':' ); if( p ) { *p++ = '\0'; user = strdup( line ); password = strdup( p ); } } msg_Dbg( p_intf, "using user=%s (read=%d)", user, i_size ); fclose( file ); } snprintf( dir, sizeof( dir ), "%s"DIR_SEP".hosts", psz_dir ); p_acl = ACL_Create( p_intf, false ); if( ACL_LoadFile( p_acl, dir ) ) { ACL_Destroy( p_acl ); struct stat st; if( utf8_stat( dir, &st ) == 0 ) { free( user ); free( password ); closedir( p_dir ); return VLC_EGENERIC; } p_acl = NULL; } for( ;; ) { char *psz_filename; /* parse psz_src dir */ if( ( psz_filename = utf8_readdir( p_dir ) ) == NULL ) { break; } if( ( psz_filename[0] == '.' ) || ( i_dirlen + strlen( psz_filename ) > MAX_DIR_SIZE ) ) { free( psz_filename ); continue; } snprintf( dir, sizeof( dir ), "%s"DIR_SEP"%s", psz_dir, psz_filename ); free( psz_filename ); if( ParseDirectory( p_intf, psz_root, dir ) ) { httpd_file_sys_t *f = NULL; httpd_handler_sys_t *h = NULL; bool b_index; char *psz_name, *psz_ext; psz_name = FileToUrl( &dir[strlen( psz_root )], &b_index ); psz_ext = strrchr( dir, '.' ); 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 = true; h->p_association = p_sys->pp_handlers[i]; } } if( f == NULL ) { f = malloc( sizeof( httpd_file_sys_t ) ); f->b_handler = false; } f->p_intf = p_intf; f->p_file = NULL; f->p_redir = NULL; f->p_redir2 = NULL; f->file = strdup (dir); f->name = psz_name; f->b_html = strstr( &dir[strlen( psz_root )], ".htm" ) || strstr( &dir[strlen( psz_root )], ".xml" ) ? true : false; if( !f->name ) { msg_Err( p_intf , "unable to parse directory" ); closedir( p_dir ); free( f ); return( VLC_ENOMEM ); } msg_Dbg( p_intf, "file=%s (url=%s)", f->file, f->name ); if( !f->b_handler ) { char *psz_type = strdup( "text/html; charset=UTF-8" ); if( strstr( &dir[strlen( psz_root )], ".xml" ) ) { char *psz = strstr( psz_type, "html;" ); if( psz ) { psz[0] = 'x'; psz[1] = 'm'; psz[2] = 'l'; psz[3] = ';'; psz[4] = ' '; } } f->p_file = httpd_FileNew( p_sys->p_httpd_host, f->name, f->b_html ? psz_type : NULL, user, password, p_acl, HttpCallback, f ); free( psz_type ); if( f->p_file != NULL ) { TAB_APPEND( p_sys->i_files, p_sys->pp_files, f ); } } else { h->p_handler = httpd_HandlerNew( p_sys->p_httpd_host, f->name, user, password, p_acl, 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/ */ if( f && f->name[strlen(f->name) - 1] == '/' ) { char *psz_redir = strdup( f->name ); char *p; psz_redir[strlen( psz_redir ) - 1] = '\0'; msg_Dbg( p_intf, "redir=%s -> %s", psz_redir, f->name ); f->p_redir = httpd_RedirectNew( p_sys->p_httpd_host, f->name, psz_redir ); free( psz_redir ); if( b_index && ( p = strstr( f->file, "index." ) ) ) { if( asprintf( &psz_redir, "%s%s", f->name, p ) != -1 ) { msg_Dbg( p_intf, "redir=%s -> %s", psz_redir, f->name ); f->p_redir2 = httpd_RedirectNew( p_sys->p_httpd_host, f->name, psz_redir ); free( psz_redir ); } } } } } free( user ); free( password ); ACL_Destroy( p_acl ); closedir( p_dir ); return VLC_SUCCESS; }