예제 #1
0
        protected override void HandleContext(HttpListenerContext context)
        {
            base.HandleContext (context);

            context.Response.SendChunked = false;
            context.Response.ContentLength64 = data.LongLength;
            context.Response.ContentType = content_type;
            context.Response.OutputStream.Write (data, 0, data.Length);

            Log.Information (string.Format (
                "{0} requested {1}.", context.Request.RemoteEndPoint, context.Request.Url));
        }
예제 #2
0
        protected override void HandleContext(HttpListenerContext context)
        {
            base.HandleContext (context);

            var method = context.Request.HttpMethod.ToUpper ();
            if (method == "SUBSCRIBE") {
                var callback = context.Request.Headers["CALLBACK"];
                if (callback != null) {
                    Subscribe (context, callback);
                } else {
                    Renew (context);
                }
            } else if (method == "UNSUBSCRIBE") {
                Unsubscribe (context);
            } else {
                Log.Warning (string.Format (
                    "A request from {0} to {1} uses an unsupported HTTP method: {2}.",
                    context.Request.RemoteEndPoint, context.Request.Url, method));
            }
        }
예제 #3
0
        void Unsubscribe(HttpListenerContext context)
        {
            var sid = context.Request.Headers["SID"];
            if (sid == null) {
                Log.Error (string.Format (
                    "An unsubscribe request from {0} to {1} did not provide an SID.",
                    context.Request.RemoteEndPoint, context.Request.Url));
                return;
            }

            Subscription subscription;
            lock (subscribers) {
                if (!subscribers.TryGetValue (sid, out subscription)) {
                    Log.Error (string.Format (
                        "An unsubscribe request from {0} to {1} was for subscription {2} which does not exist.",
                        context.Request.RemoteEndPoint, context.Request.Url, sid));
                    return;
                }
                subscribers.Remove (sid);
            }

            dispatcher.Remove (subscription.TimeoutId);

            Log.Information (string.Format ("Subscription {0} was canceled.", sid));
        }
예제 #4
0
        void Subscribe(HttpListenerContext context, string callback)
        {
            var url_string = callback.Length < 3 ? null : callback.Substring (1, callback.Length - 2);

            if (url_string == null || !Uri.IsWellFormedUriString (url_string, UriKind.Absolute)) {
                Log.Error (string.Format (
                    "The subscription request from {0} to {1} provided an illegal callback: {2}.",
                    context.Request.RemoteEndPoint, context.Request.Url, callback));
                return;
            }

            var url = new Uri (url_string);

            if (url.Scheme != Uri.UriSchemeHttp) {
                Log.Error (string.Format (
                    "The callback for the subscription request from {0} to {1} is not HTTP: {2}.",
                    context.Request.RemoteEndPoint, context.Request.Url, url));
                return;
            }

            var uuid = string.Format ("uuid:{0}", Guid.NewGuid ());
            var subscriber = new Subscription (url, uuid);

            if (!HandleSubscription (context, subscriber)) {
                Log.Error (string.Format (
                    "{0} from {1} failed to subscribe to {0}.",
                    subscriber.Callback, context.Request.RemoteEndPoint, context.Request.Url));
                return;
            }

            lock (subscribers) {
                subscribers.Add (uuid, subscriber);
            }

            Log.Information (string.Format (
                "{0} from {1} subscribed to {2} as {3}.",
                subscriber.Callback, context.Request.RemoteEndPoint, context.Request.Url, subscriber.Sid));

            // NOTE: This will cause an exception in UpnpServer when it tries to close the OutputStream
            //       I think we should be ok just closing the response and it should handle closing the OutputStream, but not sure
            // We have to finish responding with our previous context otherwise the updates don't mean anything to the client
            // The client won't have an SID so it won't make sense to publish the updates yet
            context.Response.OutputStream.Close();
            context.Response.Close();

            PublishUpdates (subscriber, state_variables);
        }
예제 #5
0
        void Renew(HttpListenerContext context)
        {
            var sid = context.Request.Headers["SID"];

            if (sid == null) {
                Log.Error (string.Format (
                    "A subscription request from {0} to {1} provided neither a CALLBACK nor a SID.",
                    context.Request.RemoteEndPoint, context.Request.Url));
                return;
            }

            Subscription subscription;
            lock (subscribers) {
                if (!subscribers.TryGetValue (sid, out subscription)) {
                    Log.Error (string.Format (
                        "A renewal request from {0} to {1} was for subscription {2} which does not exist.",
                        context.Request.RemoteEndPoint, context.Request.Url, sid));
                    return;
                }
            }

            if (!HandleSubscription (context, subscription)) {
                Log.Error (string.Format ("Failed to renew subscription {0}.", sid));
                return;
            }

            Log.Information (string.Format ("Subscription {0} was renewed.", sid));
        }
예제 #6
0
        bool HandleSubscription(HttpListenerContext context, Subscription subscriber)
        {
            dispatcher.Remove (subscriber.TimeoutId);
            var timeout = context.Request.Headers["TIMEOUT"] ?? "Second-1800";

            if (timeout != "infinite") {
                int time;
                if (timeout.Length > 7 && int.TryParse (timeout.Substring (7), out time)) {
                    subscriber.TimeoutId = dispatcher.Add (TimeSpan.FromSeconds (time), OnTimeout, subscriber.Sid);
                } else {
                    Log.Error (string.Format (
                        "Subscription request {0} from {1} to {2} has an illegal TIMEOUT value: {3}",
                        subscriber.Callback, context.Request.RemoteEndPoint, context.Request.Url, timeout));
                    return false;
                }
            }

            context.Response.AddHeader ("DATE", DateTime.Now.ToString ("r"));
            context.Response.AddHeader ("SERVER", Protocol.UserAgent);
            context.Response.AddHeader ("SID", subscriber.Sid);
            context.Response.AddHeader ("TIMEOUT", timeout);
            context.Response.StatusCode = 200;
            context.Response.StatusDescription = "OK";

            return true;
        }
예제 #7
0
        protected override void HandleContext(HttpListenerContext context)
        {
            base.HandleContext (context);

            context.Response.ContentType = @"text/xml; charset=""utf-8""";
            context.Response.AddHeader ("EXT", string.Empty);

            using (var reader = XmlReader.Create (context.Request.InputStream)) {
                // FIXME this is a workaround for mono bug 523151
                if (reader.MoveToContent () != XmlNodeType.Element) {
                    Log.Error (string.Format (
                        "A control request from {0} to {1} does not have a SOAP envelope.",
                        context.Request.RemoteEndPoint, context.Request.Url));
                    return;
                }

                SoapEnvelope<Arguments> requestEnvelope;

                try {
                    requestEnvelope = deserializer.Deserialize<SoapEnvelope<Arguments>> (reader);
                } catch (Exception e) {
                    Log.Exception (string.Format (
                        "Failed to deserialize a control request from {0} to {1}.",
                        context.Request.RemoteEndPoint, context.Request.Url), e);
                    return;
                }

                if (requestEnvelope == null) {
                    Log.Error (string.Format (
                        "A control request from {0} to {1} does not have a valid SOAP envelope.",
                        context.Request.RemoteEndPoint, context.Request.Url));
                    return;
                }

                var arguments = requestEnvelope.Body;

                if (arguments == null) {
                    Log.Error (string.Format (
                        "A control request from {0} to {1} does not have a valid argument list.",
                        context.Request.RemoteEndPoint, context.Request.Url));
                    return;
                }

                if (arguments.ActionName == null) {
                    Log.Error (string.Format (
                        "A control request from {0} to {1} does not have an action name.",
                        context.Request.RemoteEndPoint, context.Request.Url));
                    return;
                }

                ServiceAction action;

                try {
                    if (actions.TryGetValue (arguments.ActionName, out action)) {
                        Log.Information (string.Format ("{0} invoked {1} on {2}.",
                            context.Request.RemoteEndPoint, arguments.ActionName, context.Request.Url));

                        Arguments result;

                        try {
                            result = new Arguments (
                                service_type, action.Name, action.Execute (arguments.Values), true);
                        } catch (UpnpControlException) {
                            throw;
                        } catch (Exception e) {
                            throw new UpnpControlException (UpnpError.Unknown (), "Unexpected exception.", e);
                        }

                        // TODO If we're allowing consumer code to subclass Argument, then we need to expose that in a
                        // Mono.Upnp.Serializer class. We would then need to put this in a try/catch because custom
                        // serialization code could throw.
                        serializer.Serialize (new SoapEnvelope<Arguments> (result), context.Response.OutputStream);
                    } else {
                        throw new UpnpControlException (UpnpError.InvalidAction (), string.Format (
                            "{0} attempted to invoke the non-existant action {1} on {2}.",
                            context.Request.RemoteEndPoint, arguments.ActionName, context.Request.Url));
                    }
                } catch (UpnpControlException e) {
                    Log.Exception (e);

                    context.Response.StatusCode = 500;
                    context.Response.StatusDescription = "Internal Server Error";

                    // TODO This needs to be a try/catch in the future too.
                    serializer.Serialize (new SoapEnvelope<SoapFault<UpnpError>> (
                        new SoapFault<UpnpError> (e.UpnpError)), context.Response.OutputStream);
                }
            }
        }
예제 #8
0
 protected virtual void HandleContext(HttpListenerContext context)
 {
     context.Response.AppendHeader ("SERVER", Protocol.UserAgent);
     context.Response.AppendHeader ("DATE", DateTime.Now.ToUniversalTime ().ToString ("r"));
 }