示例#1
0
    def __init__(self, redirectstderrout, appname, params,
                 single_instance_checker, installdir, i2iport, sport):

        BaseApp.__init__(self, redirectstderrout, appname, params,
                         single_instance_checker, installdir, i2iport, sport)

        self.videoHTTPServer = VideoHTTPServer(VIDEOHTTP_LISTENPORT)
        self.videoHTTPServer.background_serve()
        self.videoHTTPServer.register(self.videoservthread_error_callback,
                                      self.videoservthread_set_status_callback)

        # Maps Downloads to a using InstanceConnection and streaminfo when it
        # plays. So it contains the Downloads in VOD mode for which there is
        # active interest from a plugin.
        #
        # At the moment each Download is used/owned by a single IC and a new
        # request for the same torrent will stop playback to the original IC
        # and resume it to the new user.
        #
        self.dusers = {}

        # If the BG Process is started by the plug-in notify it with an event
        startupEvent = win32event.CreateEvent(None, 0, 0, 'startupEvent')
        win32event.SetEvent(startupEvent)
        win32api.CloseHandle(
            startupEvent
        )  # TODO : is it possible to avoid importing win32api just to close an handler?
示例#2
0
    def setUp(self):
        """ unittest test setup code """
        self.port = 6789
        self.serv = VideoHTTPServer(self.port)
        self.serv.background_serve()
        self.serv.register(self.videoservthread_error_callback,
                           self.videoservthread_set_status_callback)

        self.sourcefn = os.path.join("API", "file.wmv")  # 82KB
        self.sourcesize = os.path.getsize(self.sourcefn)
    def __init__(self, redirectstderrout, appname, params,
                 single_instance_checker, installdir, i2iport, sport):

        self.videoHTTPServer = VideoHTTPServer(VIDEOHTTP_LISTENPORT)
        self.videoHTTPServer.register(self.videoservthread_error_callback,
                                      self.videoservthread_set_status_callback)
        self.videoHTTPServer.background_serve()

        #self.searchHTTPServer = MultiHTTPServer(VIDEOHTTP_LISTENPORT+1)
        #self.searchHTTPServer.register(self.videoservthread_error_callback,self.videoservthread_set_status_callback)
        self.searchHTTPServer = self.videoHTTPServer

        BaseApp.__init__(self, redirectstderrout, appname, params,
                         single_instance_checker, installdir, i2iport, sport)

        # SEARCH:P2P
        # Maps a query ID to the original searchstr, timestamp and all hits (local + remote)
        self.id2hits = Query2HitsMap()

        # Maps a URL path received by HTTP server to the requested resource,
        # reading or generating it dynamically.
        #
        # For saving .torrents received in hits to P2P searches using
        # SIMPLE+METADATA queries
        self.tqueue = TimedTaskQueue(nameprefix="BGTaskQueue")
        self.searchmapper = SearchPathMapper(self.s, self.id2hits, self.tqueue)
        self.hits2anypathmapper = Hits2AnyPathMapper(self.s, self.id2hits)

        self.searchHTTPServer.add_path_mapper(self.searchmapper)
        self.searchHTTPServer.add_path_mapper(self.hits2anypathmapper)
        self.searchHTTPServer.background_serve()
        self.searchurl = 'http://127.0.0.1:' + str(
            self.searchHTTPServer.get_port()) + URLPATH_SEARCH_PREFIX

        # Maps Downloads to a using InstanceConnection and streaminfo when it
        # plays. So it contains the Downloads in VOD mode for which there is
        # active interest from a plugin.
        #
        # At the moment each Download is used/owned by a single IC and a new
        # request for the same torrent will stop playback to the original IC
        # and resume it to the new user.
        #
        self.dusers = {}
        self.approxplayerstate = MEDIASTATE_STOPPED

        self.counter = 0  # counter for the stats reported periodically
        self.interval = 120  # report interval

        if sys.platform == "win32":
            # If the BG Process is started by the plug-in notify it with an event
            startupEvent = win32event.CreateEvent(None, 0, 0, 'startupEvent')
            win32event.SetEvent(startupEvent)
            win32api.CloseHandle(
                startupEvent
            )  # TODO : is it possible to avoid importing win32api just to close an handler?
示例#4
0
class HTTPSeeder:
    def __init__(self):
        self.videoHTTPServer = VideoHTTPServer(VIDEOHTTP_LISTENPORT)
        self.videoHTTPServer.register(self.videoservthread_error_callback, self.videoservthread_set_status_callback)
        self.videoHTTPServer.background_serve()

    #
    # VideoServer status/error reporting
    #
    def videoservthread_error_callback(self, e, url):
        print >>sys.stderr, "httpseed: Video server reported error", url, str(e)

    def videoservthread_set_status_callback(self, status):
        print >>sys.stderr, "httpseed: Video server sets status callback", status
示例#5
0
    def register(self,utility,preferredplaybackmode=None,closeextplayercallback=None):
        
        self.utility = utility # TEMPARNO: make sure only used for language strings

        self.preferredplaybackmode = preferredplaybackmode
        self.determine_playbackmode()

        if self.playbackmode == PLAYBACKMODE_INTERNAL:
            # The python-vlc bindings. Created only once at the moment,
            # as using MediaControl.exit() more than once with the raw interface
            # blows up the GUI.
            #
            from BaseLib.Video.VLCWrapper import VLCWrapper
            self.vlcwrap = VLCWrapper(self.utility.getPath())
            self.supportedvodevents = [VODEVENT_START,VODEVENT_PAUSE,VODEVENT_RESUME]
        else:
            self.vlcwrap = None
            # Can't pause when external player
            self.supportedvodevents = [VODEVENT_START]
            
        if self.playbackmode != PLAYBACKMODE_INTERNAL or not USE_VLC_RAW_INTERFACE:
            # Start HTTP server for serving video to external player
            self.videohttpserv = VideoHTTPServer.getInstance(self.videohttpservport) # create
            self.videohttpserv.background_serve()
            self.videohttpserv.register(self.videohttpserver_error_callback,self.videohttpserver_set_status_callback)
            
        if closeextplayercallback is not None:
            self.closeextplayercallback = closeextplayercallback
class TestVideoHTTPServer(unittest.TestCase):
    """ 
    Class for testing HTTP-based video server.
    
    Mainly HTTP range queries.
    """
    
    def setUp(self):
        """ unittest test setup code """
        self.port = 6789
        self.serv = VideoHTTPServer(self.port)
        self.serv.background_serve()
        self.serv.register(self.videoservthread_error_callback,self.videoservthread_set_status_callback)
        
        self.sourcefn = os.path.join("API","file.wmv") # 82KB
        self.sourcesize = os.path.getsize(self.sourcefn)
         
    def tearDown(self):
        """ unittest test tear down code """
        print >>sys.stderr,"test: Tear down, sleeping 10 s"
        time.sleep(10)
    
    def videoservthread_error_callback(self,e,url):
        """ Called by HTTP serving thread """
        print >>sys.stderr,"test: ERROR",e,url
        self.assert_(False)
        
    def videoservthread_set_status_callback(self,status):
        """ Called by HTTP serving thread """
        print >>sys.stderr,"test: STATUS",status
    

    #
    # Tests
    #
    def test_ranges(self):
        # Run single test, VideoHTTPServer is singleton at the moment and
        # doesn't like recreate.
        try:
            self.range_test(115,214,100)
            self.range_test(self.sourcesize-100,None,100)
            self.range_test(None,100,100)

            self.range_test(115,214,100,setset=True)
            
        except Exception,e:
            print_exc()
示例#7
0
class TestVideoHTTPServer(unittest.TestCase):
    """ 
    Class for testing HTTP-based video server.
    
    Mainly HTTP range queries.
    """
    def setUp(self):
        """ unittest test setup code """
        self.port = 6789
        self.serv = VideoHTTPServer(self.port)
        self.serv.background_serve()
        self.serv.register(self.videoservthread_error_callback,
                           self.videoservthread_set_status_callback)

        self.sourcefn = os.path.join("API", "file.wmv")  # 82KB
        self.sourcesize = os.path.getsize(self.sourcefn)

    def tearDown(self):
        """ unittest test tear down code """
        print >> sys.stderr, "test: Tear down, sleeping 10 s"
        time.sleep(10)

    def videoservthread_error_callback(self, e, url):
        """ Called by HTTP serving thread """
        print >> sys.stderr, "test: ERROR", e, url
        self.assert_(False)

    def videoservthread_set_status_callback(self, status):
        """ Called by HTTP serving thread """
        print >> sys.stderr, "test: STATUS", status

    #
    # Tests
    #
    def test_ranges(self):
        # Run single test, VideoHTTPServer is singleton at the moment and
        # doesn't like recreate.
        try:
            self.range_test(115, 214, 100)
            self.range_test(self.sourcesize - 100, None, 100)
            self.range_test(None, 100, 100)

            self.range_test(115, 214, 100, setset=True)

        except Exception, e:
            print_exc()
示例#8
0
    def __init__(self, redirectstderrout, appname, appversion, params, single_instance_checker, installdir, i2iport, sport, httpport):

        # Almost generic HTTP server
        self.videoHTTPServer = VideoHTTPServer(httpport)
        self.videoHTTPServer.register(self.videoservthread_error_callback,self.videoservthread_set_status_callback)

        BaseApp.__init__(self, redirectstderrout, appname, appversion, params, single_instance_checker, installdir, i2iport, sport)
        self.httpport = httpport
        
        # SEARCH:P2P
        # Maps a query ID to the original searchstr, timestamp and all hits (local + remote)
        self.id2hits = Query2HitsMap()
        
        # Maps a URL path received by HTTP server to the requested resource,
        # reading or generating it dynamically.
        #
        # For saving .torrents received in hits to P2P searches using
        # SIMPLE+METADATA queries
        self.tqueue = TimedTaskQueue(nameprefix="BGTaskQueue")
        self.searchmapper = SearchPathMapper(self.s,self.id2hits,self.tqueue)
        self.hits2anypathmapper = Hits2AnyPathMapper(self.s,self.id2hits)
        
        self.videoHTTPServer.add_path_mapper(self.searchmapper)
        self.videoHTTPServer.add_path_mapper(self.hits2anypathmapper)

        # WEB Interface        
        # Maps a URL path received by HTTP server to the requested resource,
        # reading or generating it dynamically.
        self.webIFmapper = WebIFPathMapper(self, self.s)
        
        self.videoHTTPServer.add_path_mapper(self.webIFmapper)

        # Generic HTTP server start. Don't add mappers dynamically afterwards!
        self.videoHTTPServer.background_serve()

        # Maps Downloads to a using InstanceConnection and streaminfo when it 
        # plays. So it contains the Downloads in VOD mode for which there is
        # active interest from a plugin.
        #
        # At the moment each Download is used/owned by a single IC and a new
        # request for the same torrent will stop playback to the original IC
        # and resume it to the new user.
        #
        self.dusers = {}   
        self.approxplayerstate = MEDIASTATE_STOPPED

        self.counter = 0 # counter for the stats reported periodically
        self.interval = 120 # report interval
        self.iseedeadpeople = False
        
        if sys.platform == "win32":
            # If the BG Process is started by the plug-in notify it with an event
            try:
                startupEvent = win32event.CreateEvent( None, 0, 0, 'startupEvent' )
                win32event.SetEvent( startupEvent )
                win32api.CloseHandle( startupEvent ) # TODO : is it possible to avoid importing win32api just to close an handler?
            except:
                pass
示例#9
0
 def setUp(self):
     """ unittest test setup code """
     self.port = 6789
     self.serv = VideoHTTPServer(self.port)
     self.serv.background_serve()
     self.serv.register(self.videoservthread_error_callback,self.videoservthread_set_status_callback)
     
     self.sourcefn = os.path.join("API","file.wmv") # 82KB or 82948 bytes
     self.sourcesize = os.path.getsize(self.sourcefn)
    def __init__(self, redirectstderrout, appname, params, single_instance_checker, installdir, i2iport, sport):

        self.videoHTTPServer = VideoHTTPServer(VIDEOHTTP_LISTENPORT)
        self.videoHTTPServer.register(self.videoservthread_error_callback,self.videoservthread_set_status_callback)
        self.videoHTTPServer.background_serve()

        #self.searchHTTPServer = MultiHTTPServer(VIDEOHTTP_LISTENPORT+1)
        #self.searchHTTPServer.register(self.videoservthread_error_callback,self.videoservthread_set_status_callback)
        self.searchHTTPServer = self.videoHTTPServer

        BaseApp.__init__(self, redirectstderrout, appname, params, single_instance_checker, installdir, i2iport, sport)
        
        # SEARCH:P2P
        # Maps a query ID to the original searchstr, timestamp and all hits (local + remote)
        self.id2hits = Query2HitsMap()
        
        # Maps a URL path received by HTTP server to the requested resource,
        # reading or generating it dynamically.
        #
        # For saving .torrents received in hits to P2P searches using
        # SIMPLE+METADATA queries
        self.tqueue = TimedTaskQueue(nameprefix="BGTaskQueue")
        self.searchmapper = SearchPathMapper(self.s,self.id2hits,self.tqueue)
        self.hits2anypathmapper = Hits2AnyPathMapper(self.s,self.id2hits)
        
        self.searchHTTPServer.add_path_mapper(self.searchmapper)
        self.searchHTTPServer.add_path_mapper(self.hits2anypathmapper)
        self.searchHTTPServer.background_serve()
        self.searchurl = 'http://127.0.0.1:'+str(self.searchHTTPServer.get_port())+URLPATH_SEARCH_PREFIX


        # Maps Downloads to a using InstanceConnection and streaminfo when it 
        # plays. So it contains the Downloads in VOD mode for which there is
        # active interest from a plugin.
        #
        # At the moment each Download is used/owned by a single IC and a new
        # request for the same torrent will stop playback to the original IC
        # and resume it to the new user.
        #
        self.dusers = {}   
        self.approxplayerstate = MEDIASTATE_STOPPED

        self.counter = 0 # counter for the stats reported periodically
        self.interval = 120 # report interval
        
        if sys.platform == "win32":
            # If the BG Process is started by the plug-in notify it with an event
            startupEvent = win32event.CreateEvent( None, 0, 0, 'startupEvent' )
            win32event.SetEvent( startupEvent )
            win32api.CloseHandle( startupEvent ) # TODO : is it possible to avoid importing win32api just to close an handler?
class BackgroundApp(BaseApp):
    def __init__(self, redirectstderrout, appname, params, single_instance_checker, installdir, i2iport, sport):

        BaseApp.__init__(self, redirectstderrout, appname, params, single_instance_checker, installdir, i2iport, sport)

        self.videoHTTPServer = VideoHTTPServer(VIDEOHTTP_LISTENPORT)
        self.videoHTTPServer.background_serve()
        self.videoHTTPServer.register(self.videoservthread_error_callback, self.videoservthread_set_status_callback)

        # Maps Downloads to a using InstanceConnection and streaminfo when it
        # plays. So it contains the Downloads in VOD mode for which there is
        # active interest from a plugin.
        #
        # At the moment each Download is used/owned by a single IC and a new
        # request for the same torrent will stop playback to the original IC
        # and resume it to the new user.
        #
        self.dusers = {}

        # If the BG Process is started by the plug-in notify it with an event
        startupEvent = win32event.CreateEvent(None, 0, 0, "startupEvent")
        win32event.SetEvent(startupEvent)
        win32api.CloseHandle(
            startupEvent
        )  # TODO : is it possible to avoid importing win32api just to close an handler?

    def OnInit(self):
        try:
            # Do common initialization
            BaseApp.OnInitBase(self)
            return True

        except Exception, e:
            print_exc()
            self.show_error(str(e))
            self.OnExit()
            return False
示例#12
0
def vod_ready_callback(d,event,params):
    print >>sys.stderr,"main: VOD ready callback called",currentThread().getName(),"###########################################################",params["mimetype"]

    """
    f = open("video.avi","wb")
    while True:
        data = stream.read()
        print >>sys.stderr,"main: VOD ready callback: reading",type(data)
        print >>sys.stderr,"main: VOD ready callback: reading",len(data)
        if len(data) == 0:
            break
        f.write(data)
    f.close()
    stream.close()
    """

    videoserv = VideoHTTPServer.getInstance()
    videoserv.set_inputstream('video/mpeg',params["stream"],None)
示例#13
0
    def register(self,
                 utility,
                 preferredplaybackmode=None,
                 closeextplayercallback=None):

        self.utility = utility  # TEMPARNO: make sure only used for language strings

        self.preferredplaybackmode = preferredplaybackmode
        self.determine_playbackmode()

        if self.playbackmode == PLAYBACKMODE_INTERNAL:
            # The python-vlc bindings. Created only once at the moment,
            # as using MediaControl.exit() more than once with the raw interface
            # blows up the GUI.
            #
            from BaseLib.Video.VLCWrapper import VLCWrapper
            self.vlcwrap = VLCWrapper(self.utility.getPath())
            self.supportedvodevents = [
                VODEVENT_START, VODEVENT_PAUSE, VODEVENT_RESUME
            ]
        else:
            self.vlcwrap = None
            # Can't pause when external player
            self.supportedvodevents = [VODEVENT_START]

        if self.playbackmode != PLAYBACKMODE_INTERNAL or not USE_VLC_RAW_INTERFACE:
            # Start HTTP server for serving video to external player
            self.videohttpserv = VideoHTTPServer.getInstance(
                self.videohttpservport)  # create
            self.videohttpserv.background_serve()
            self.videohttpserv.register(
                self.videohttpserver_error_callback,
                self.videohttpserver_set_status_callback)

        if closeextplayercallback is not None:
            self.closeextplayercallback = closeextplayercallback
示例#14
0
        print >>sys.stderr,"main: VOD ready callback: reading",type(data)
        print >>sys.stderr,"main: VOD ready callback: reading",len(data)
        if len(data) == 0:
            break
        f.write(data)
    f.close()
    stream.close()
    """

    videoserv = VideoHTTPServer.getInstance()
    videoserv.set_inputstream('video/mpeg',params["stream"],None)
    

if __name__ == "__main__":
    
    videoserv = VideoHTTPServer.getInstance() # create
    videoserv.background_serve()
    
    s = Session()
    
    if sys.platform == 'win32':
        tdef = TorrentDef.load('bla.torrent')
    else:
        tdef = TorrentDef.load('/tmp/bla.torrent')
    dcfg = DownloadStartupConfig.get_copy_of_default()
    #dcfg.set_saveas('/arno')
    dcfg = DownloadStartupConfig.get_copy_of_default()
    dcfg.set_video_start_callback(vod_ready_callback)
    #dcfg.set_selected_files('MATRIX-XP_engl_L.avi') # play this video
    #dcfg.set_selected_files('field-trip-west-siberia.avi')
    
示例#15
0
class BackgroundApp(BaseApp):

    def __init__(self, logdir, appname, appversion, params, single_instance_checker, installdir, i2iport, sport, httpport, ws_serverport, bt_port):
	# Running WebSocket server SockJS Tornado
        Router = SockJSRouter(WsConnection, '/websocket')
    	ws_serv = WsServer(i2iport,ws_serverport)
    	ws_serv.start()

        # Almost generic HTTP server
        self.videoHTTPServer = VideoHTTPServer(httpport)
        self.videoHTTPServer.register(self.videoservthread_error_callback,self.videoservthread_set_status_callback)

        # Running BitTorrent HTTP server
        self.q = Queue()
        self.p = Process(target=serveHTTP, args=(self.q,))
        self.p.start()

	period_upnp()

        BaseApp.__init__(self, logdir, appname, appversion, params, single_instance_checker, installdir, i2iport, sport)
        self.httpport = httpport
        
        # SEARCH:P2P
        # Maps a query ID to the original searchstr, timestamp and all hits (local + remote)
        self.id2hits = Query2HitsMap()
        
        # Maps a URL path received by HTTP server to the requested resource,
        # reading or generating it dynamically.
        #
        # For saving .torrents received in hits to P2P searches using
        # SIMPLE+METADATA queries
        self.tqueue = TimedTaskQueue(nameprefix="BGTaskQueue")
        self.searchmapper = SearchPathMapper(self.s,self.id2hits,self.tqueue)
        self.hits2anypathmapper = Hits2AnyPathMapper(self.s,self.id2hits)
        
        self.videoHTTPServer.add_path_mapper(self.searchmapper)
        self.videoHTTPServer.add_path_mapper(self.hits2anypathmapper)

        # WEB Interface        
        # Maps a URL path received by HTTP server to the requested resource,
        # reading or generating it dynamically.
        self.webIFmapper = WebIFPathMapper(self, self.s)
        
        self.videoHTTPServer.add_path_mapper(self.webIFmapper)

        # Generic HTTP server start. Don't add mappers dynamically afterwards!
        self.videoHTTPServer.background_serve()
        
        # Maps Downloads to a using InstanceConnection and streaminfo when it 
        # plays. So it contains the Downloads in VOD mode for which there is
        # active interest from a plugin.
        #
        # At the moment each Download is used/owned by a single IC and a new
        # request for the same torrent will stop playback to the original IC
        # and resume it to the new user.
        #
        self.dusers = {}   
        self.approxplayerstate = MEDIASTATE_STOPPED

        self.counter = 0 # counter for the stats reported periodically
        self.interval = 120 # report interval
        self.iseedeadpeople = False
        
        if sys.platform == "win32":
            # If the BG Process is started by the plug-in notify it with an event
            try:
                startupEvent = win32event.CreateEvent( None, 0, 0, 'startupEvent' )
                win32event.SetEvent( startupEvent )
                win32api.CloseHandle( startupEvent ) # TODO : is it possible to avoid importing win32api just to close an handler?
            except:
                pass

    def OnInit(self):
        try:
            # Do common initialization
            BaseApp.OnInitBase(self)
            
            # Arno, 2010-07-15: We try to detect browser presence by looking
            # at get_speed_info JSON request from Firefox statusbar. However.
            # these calls are unreliable, i.e., somethings the XmlHTTPRequest
            # at the client doesn't reach the server, although the server is
            # capable of replying to the request. Hence, we disable self-destruct
            # for now.
            if KILLONIDLE:
                print >>sys.stderr,time.asctime(),'-', "bg: Kill-on-idle test enabled"
                self.i2is.add_task(self.i2i_kill_on_browser_gone,IDLE_BEFORE_SELFKILL/2)
            else:
                print >>sys.stderr,time.asctime(),'-', "bg: Kill-on-idle test disabled"
            
            print >>sys.stderr,time.asctime(),'-', "bg: Awaiting commands"
            return True

        except Exception,e:
            print_exc()
            self.show_error(str(e))
            self.OnExit()
            return False
示例#16
0
 def __init__(self):
     self.videoHTTPServer = VideoHTTPServer(VIDEOHTTP_LISTENPORT)
     self.videoHTTPServer.register(self.videoservthread_error_callback, self.videoservthread_set_status_callback)
     self.videoHTTPServer.background_serve()
示例#17
0
class TestVideoHTTPServer(unittest.TestCase):
    """ 
    Class for testing HTTP-based video server.
    
    Mainly HTTP range queries.
    """
    
    def setUp(self):
        """ unittest test setup code """
        self.port = 6789
        self.serv = VideoHTTPServer(self.port)
        self.serv.background_serve()
        self.serv.register(self.videoservthread_error_callback,self.videoservthread_set_status_callback)
        
        self.sourcefn = os.path.join("API","file.wmv") # 82KB or 82948 bytes
        self.sourcesize = os.path.getsize(self.sourcefn)
         
    def tearDown(self):
        """ unittest test tear down code """
        print >>sys.stderr,time.asctime(),'-', "test: Tear down, sleeping 10 s"
        time.sleep(10)
    
    def videoservthread_error_callback(self,e,url):
        """ Called by HTTP serving thread """
        print >>sys.stderr,time.asctime(),'-', "test: ERROR",e,url
        self.assert_(False)
        
    def videoservthread_set_status_callback(self,status):
        """ Called by HTTP serving thread """
        print >>sys.stderr,time.asctime(),'-', "test: STATUS",status
    

    #
    # Tests
    #
    def test_ranges(self):
        # Run single test, VideoHTTPServer is singleton at the moment and
        # doesn't like recreate.
        self.range_test(115,214,self.sourcesize)
        self.range_test(self.sourcesize-100,None,self.sourcesize)
        self.range_test(None,100,self.sourcesize)
        self.range_test(115,214,self.sourcesize,setset=True)

    #
    # Internal
    #
    def register_file_stream(self):
        stream = open(self.sourcefn,"rb")

        streaminfo = { 'mimetype': 'video/x-ms-wmv', 'stream': stream, 'length': self.sourcesize }
        
        self.serv.set_inputstream(streaminfo,"/stream")

    def get_std_header(self):
        msg =  "GET /stream HTTP/1.1\r\n"
        msg += "Host: 127.0.0.1:"+str(self.port)+"\r\n"
        return msg

    def create_range_str(self,firstbyte,lastbyte):
        head = "" 
        if firstbyte is not None:
            head += str(firstbyte)
        head += "-"
        if lastbyte is not None:
            head += str(lastbyte)
            
        return head

    def range_test(self,firstbyte,lastbyte,sourcesize,setset=False):
        print >>sys.stderr,time.asctime(),'-', "test: range_test:",firstbyte,lastbyte,sourcesize,"setset",setset
        self.register_file_stream()
        
        s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
        s.connect(('127.0.0.1', self.port))

        head = self.get_std_header()
        
        head += "Range: bytes="
        head += self.create_range_str(firstbyte,lastbyte)
        if setset:
            # Make into set of byte ranges, VideoHTTPServer should refuse.
            head += ",0-99"
        head += "\r\n"
        
        head += "Connection: close\r\n"
        
        head += "\r\n"
        
        if firstbyte is not None and lastbyte is None:
            # 100-
            expfirstbyte = firstbyte 
            explastbyte = self.sourcesize-1
        elif firstbyte is None and lastbyte is not None:
            # -100
            expfirstbyte = self.sourcesize-lastbyte 
            explastbyte = self.sourcesize-1
        else:
            expfirstbyte = firstbyte
            explastbyte = lastbyte

        # the amount of bytes actually requested. (Content-length)
        expsize = explastbyte - expfirstbyte + 1

        print >>sys.stderr,time.asctime(),'-', "test: Expecting first",expfirstbyte,"last",explastbyte,"size",sourcesize
        s.send(head)
        
        # Parse header
        s.settimeout(10.0)
        while True:
            line = self.readline(s)
            
            print >>sys.stderr,time.asctime(),'-', "test: Got line",`line`
            
            if len(line)==0:
                print >>sys.stderr,time.asctime(),'-', "test: server closed conn"
                self.assert_(False)
                return
            
            if line.startswith("HTTP"):
                if not setset:
                    # Python returns "HTTP/1.0 206 Partial Content\r\n" HTTP 1.0???
                    self.assert_(line.startswith("HTTP/1."))
                    self.assert_(line.find("206") != -1) # Partial content
                else:
                    self.assert_(line.startswith("HTTP/1."))
                    self.assert_(line.find("416") != -1) # Requested Range Not Satisfiable
                    return

            elif line.startswith("Content-Range:"):
                expline = "Content-Range: bytes "+self.create_range_str(expfirstbyte,explastbyte)+"/"+str(sourcesize)+"\r\n"
                self.assertEqual(expline,line)
                 
            elif line.startswith("Content-Type:"):
                self.assertEqual(line,"Content-Type: video/x-ms-wmv\r\n")
                
            elif line.startswith("Content-Length:"):
                self.assertEqual(line,"Content-Length: "+str(expsize)+"\r\n")

            elif line.endswith("\r\n") and len(line) == 2:
                # End of header
                break
        
        data = s.recv(expsize)
        if len(data) == 0:
            print >>sys.stderr,time.asctime(),'-', "test: server closed conn2"
            self.assert_(False)
            return
        else:
            f = open(self.sourcefn,"rb")
            if firstbyte is not None:
                f.seek(firstbyte)
            else:
                f.seek(lastbyte,os.SEEK_END)

            expdata = f.read(expsize)
            f.close()
            self.assert_(data,expdata)

            try:
                # Readed body, reading more should EOF (we disabled persist conn)
                data = s.recv(10240)
                self.assert_(len(data) == 0)
        
            except socket.timeout:
                print >> sys.stderr,time.asctime(),'-', "test: Timeout, video server didn't respond with requested bytes, possibly bug in Python impl of HTTP"
                print_exc()

    def readline(self,s):
        line = ''
        while True:
            data = s.recv(1)
            if len(data) == 0:
                return line
            else:
                line = line+data
            if data == '\n' and len(line) >= 2 and line[-2:] == '\r\n':
                return line