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)); }
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)); } }
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)); }
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); }
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)); }
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; }
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); } } }
protected virtual void HandleContext(HttpListenerContext context) { context.Response.AppendHeader ("SERVER", Protocol.UserAgent); context.Response.AppendHeader ("DATE", DateTime.Now.ToUniversalTime ().ToString ("r")); }