def handle_info(self, request: HttpRequest) -> Optional[HttpResponse]: """Handle incoming info request.""" if not self.state.info_supported: return HttpResponse( "RTSP", "1.0", 400, "Bad Request", { "CSeq": request.headers["CSeq"], }, b"", ) info = {} if self.state.initial_audio_level_supported: info["initialVolume"] = self.state.volume return HttpResponse( "RTSP", "1.0", 200, "OK", { "CSeq": request.headers["CSeq"], "content-type": "application/x-apple-binary-plist", }, plistlib.dumps(info), )
def handle_auth_setup(self, request: HttpRequest) -> Optional[HttpResponse]: _LOGGER.debug("Received auth-setup: %s", request) # Just check if decent sized payload is there if len(request.body) == 1 + 32: # auth type + public key self.state.auth_setup_performed = True return HttpResponse("RTSP", "1.0", 200, "OK", {"CSeq": request.headers["CSeq"]}, b"") return HttpResponse("RTSP", "1.0", 403, "Forbidden", {"CSeq": request.headers["CSeq"]}, b"")
def handle_feedback(self, request: HttpRequest) -> Optional[HttpResponse]: """Handle incoming feedback request.""" _LOGGER.debug("Received feedback: %s", request) self.state.feedback_packets_received += 1 if not self.state.supports_feedback: return HttpResponse( "RTSP", "1.0", 501, "Not implemented", {"CSeq": request.headers["CSeq"]}, b"", ) return HttpResponse("RTSP", "1.0", 200, "OK", {"CSeq": request.headers["CSeq"]}, b"")
def _handle_page(request: HttpRequest): assert request.protocol == "HTTP" assert request.version == "1.1" assert request.path == "/resource" assert request.method == "GET" return HttpResponse("HTTP", "1.1", 200, "OK", {"DummyHeader": "value"}, b"body")
def handle_announce(self, request: HttpRequest) -> Optional[HttpResponse]: """Handle incoming ANNOUNCE request.""" _LOGGER.debug("Received ANNOUNCE: %s", request) for line in request.body.decode("utf-8").split("\r\n"): if line.startswith("o="): self.state.remote_address = line.split()[-1] break return HttpResponse("RTSP", "1.0", 200, "OK", {"CSeq": request.headers["CSeq"]}, b"")
def handle_set_parameter(self, request: HttpRequest) -> Optional[HttpResponse]: """Handle incoming SET_PARAMETER request.""" _LOGGER.debug("Received SET_PARAMETER: %s", request) if request.headers["Content-Type"] == "application/x-dmap-tagged": tags = parser.parse(request.body, lookup_tag) self.state.metadata.title = parser.first(tags, "mlit", "minm") self.state.metadata.artist = parser.first(tags, "mlit", "asar") self.state.metadata.album = parser.first(tags, "mlit", "asal") return HttpResponse("RTSP", "1.0", 200, "OK", {"CSeq": request.headers["CSeq"]}, b"")
def _impl(self, request: HttpRequest, *args, **kwargs): # No password required if not self.state.password: return method(self, request, *args, **kwargs) # Send a challenge if not self.state.nonce: nonce = self.state.nonce = "".join( random.choices(string.ascii_letters + string.digits, k=32)) return HttpResponse( "RTSP", "1.0", 401, "Unauthorized", { "CSeq": request.headers["CSeq"], "WWW-Authenticate": f'Digest realm="{REALM}", nonce="{nonce}"', }, b"", ) # Verify the authentication payload send by the client payload_data = request.headers.get("Authorization", "").split('"') if len(payload_data) == 11: uri = request.path user = payload_data[1] actual_response = payload_data[9] nonce = self.state.nonce pwd = self.state.password ha1 = md5(f"{user}:{REALM}:{pwd}".encode("utf-8")).hexdigest() ha2 = md5(f"{request.method}:{uri}".encode("utf-8")).hexdigest() expected_response = md5( f"{ha1}:{nonce}:{ha2}".encode("utf-8")).hexdigest() if actual_response == expected_response: return method(self, request, *args, **kwargs) # Password verification failed return HttpResponse("RTSP", "1.0", 401, "Unauthorized", {"CSeq": request.headers["CSeq"]}, b"")
def handle_set_parameter(self, request: HttpRequest) -> Optional[HttpResponse]: """Handle incoming SET_PARAMETER request.""" _LOGGER.debug("Received SET_PARAMETER: %s", request) if request.headers["Content-Type"] == "application/x-dmap-tagged": tags = parser.parse(request.body, lookup_tag) self.state.metadata.title = parser.first(tags, "mlit", "minm") self.state.metadata.artist = parser.first(tags, "mlit", "asar") self.state.metadata.album = parser.first(tags, "mlit", "asal") elif request.body.startswith("volume:"): self.state.volume = float(request.body.split(" ", maxsplit=1)[1]) _LOGGER.debug("Changing volume to %f", self.state.volume) else: return HttpResponse( "RTSP", "1.0", 501, "Not implemented", {"CSeq": request.headers["CSeq"]}, b"", ) return HttpResponse("RTSP", "1.0", 200, "OK", {"CSeq": request.headers["CSeq"]}, b"")
def handle_setup(self, request: HttpRequest) -> Optional[HttpResponse]: """Handle incoming SETUP request.""" _LOGGER.debug("Received SETUP: %s", request) _, options = parse_transport(request.headers["Transport"]) self.state.control_port = int(options["control_port"]) headers = { "Transport": ("RTP/AVP/UDP;unicast;mode=record;" f"server_port={self._audio_receiver.port};" f"control_port={self._control_server.port};" f"timing_port={self._timing_server.port}"), "Session": "1", "CSeq": request.headers["CSeq"], } return HttpResponse("RTSP", "1.0", 200, "OK", headers, b"")
def handle_record(self, request: HttpRequest) -> Optional[HttpResponse]: """Handle incoming RECORD request.""" _LOGGER.debug("Received RECORD: %s", request) return HttpResponse("RTSP", "1.0", 200, "OK", {"CSeq": request.headers["CSeq"]}, b"")
def handle_feedback(self, request: HttpRequest) -> Optional[HttpResponse]: """Handle incoming feedback request.""" _LOGGER.debug("Received feedback: %s", request) return HttpResponse("RTSP", "1.0", 200, "OK", {"CSeq": request.headers["CSeq"]}, b"")
def bar(self, request: HttpRequest) -> Optional[HttpResponse]: return HttpResponse("HTTP", "1.1", 123, "dummy", {}, request.body)
def foo(self, request: HttpRequest) -> Optional[HttpResponse]: return HttpResponse("HTTP", "1.1", 200, "foo", {}, request.body)
def handle_teardown(self, request: HttpRequest) -> Optional[HttpResponse]: """Handle incoming TEARDOWN request.""" self.state.teardown_called = True return HttpResponse("RTSP", "1.0", 200, "OK", {"CSeq": request.headers["CSeq"]}, b"")
def _impl(self, request: HttpRequest, *args, **kwargs): if self.state.auth_required and not self.state.auth_setup_performed: return HttpResponse("RTSP", "1.0", 403, "Forbidden", {"CSeq": request.headers["CSeq"]}, b"") return method(self, request, *args, **kwargs)