Serve a ``NOTIFY`` request.

        A ``NOTIFY`` request will be sent by a Sonos device when a state
        variable changes. See the `UPnP Spec §4.3 [pdf]
        <http://upnp.org/specs/arch/UPnP-arch
        -DeviceArchitecture-v1.1.pdf>`_  for details.

def do_NOTIFY(self):  # pylint: disable=invalid-name
        """Serve a ``NOTIFY`` request.

        A ``NOTIFY`` request will be sent by a Sonos device when a state
        variable changes. See the `UPnP Spec §4.3 [pdf]
        <http://upnp.org/specs/arch/UPnP-arch
        -DeviceArchitecture-v1.1.pdf>`_  for details.
        """
        timestamp = time.time()
        headers = requests.structures.CaseInsensitiveDict(self.headers)
        seq = headers['seq']  # Event sequence number
        sid = headers['sid']  # Event Subscription Identifier
        content_length = int(headers['content-length'])
        content = self.rfile.read(content_length)
        # Find the relevant service and queue from the sid
        with _subscriptions_lock:
            subscription = _subscriptions.get(sid)
        # It might have been removed by another thread
        if subscription:
            service = subscription.service
            log.info(
                "Event %s received for %s service on thread %s at %s", seq,
                service.service_id, threading.current_thread(), timestamp)
            log.debug("Event content: %s", content)
            variables = parse_event_xml(content)
            # Build the Event object
            event = Event(sid, seq, service, timestamp, variables)
            # pass the event details on to the service so it can update its
            # cache.
            # pylint: disable=protected-access
            service._update_cache_on_event(event)
            # Put the event on the queue
            subscription.events.put(event)
        else:
            log.info("No service registered for %s", sid)
        self.send_response(200)
        self.end_headers()