Ejemplo n.º 1
0
 void IHttpCwsHandler.ProcessRequest(HttpCwsContext context)
 {
     try
     {
         if (context.Request.RouteData == null)
         {
             return;
         }
         else
         {
             string action = context.Request.HttpMethod + context.Request.RouteData.Route.Name.ToUpper();
             switch (action)
             {
             case "GETVARIABLES":
                 context.Response.ContentType = "application/json";
                 context.Response.Write(MvMain.getMagicVariablesSerialized(), true);
                 break;
             }
         }
     }
     catch (Exception ex)
     {
         context.Response.ContentType = "text/html";
         context.Response.StatusCode  = 500;
         context.Response.Write("<HTML><HEAD>ERROR</HEAD><BODY>Internal server error</BODY></HEAD></HTML>", true);
     }
 }
Ejemplo n.º 2
0
        /// <summary>
        /// Send an HTTP error response by specifying the status code and message.
        /// In the case of a 405 response, the caller should also include the allowed
        /// HTTP methods for the requested resource
        /// </summary>
        /// <param name="context"></param>
        /// <param name="code"></param>
        /// <param name="errorMsg"></param>
        /// <param name="allowedMethods"></param>
        void SendError(HttpCwsContext context, int code, string errorMsg, params string[] allowedMethods)
        {
            context.Response.StatusCode        = code;
            context.Response.StatusDescription = statusDescriptions[code];
            if (code == 405)
            {
                string allowHeader = "";
                // Add each allowed method in a comma-separated list
                for (int i = 0; i < allowedMethods.Length; i++)
                {
                    allowHeader += allowedMethods[i].ToUpper();
                    if (i != allowedMethods.Length - 1)
                    {
                        allowHeader += ", ";
                    }
                }
                // Add the finished header to the HTTP response and to the response body
                context.Response.AppendHeader("Allow", allowHeader);
            }

            // Send the error response
            context.Response.ContentType = "text/html";
            context.Response.Write(CreateHtmlBody(errorHtml,
                                                  new NameValueCollection()
            {
                { "error", errorMsg }
            }),
                                   true);
        }
Ejemplo n.º 3
0
        /// <summary>
        /// Provides processing of HTTP requests by a HttpHandler that implements
        ///                 the <see cref="T:Crestron.SimplSharp.WebScripting.IHttpCwsHandler"/> interface.
        /// </summary>
        /// <param name="context">The object encapsulating the HTTP request.</param>
        /// <returns>
        /// true is the request was processed successfully; otherwise, false.
        /// </returns>
        public virtual void ProcessRequest(HttpCwsContext context)
        {
            try
            {
                _context = context;
                switch (_context.Request.HttpMethod)
                {
                case "GET":
                    try
                    {
                        Get();
                    }
                    catch (Exception e)
                    {
                        if (e is NotImplementedException)
                        {
                            Error(405, "Method not allowed");
                        }
                        else
                        {
                            Error(e);
                        }
                    }
                    break;

                case "POST":
                    try
                    {
                        Post();
                    }
                    catch (Exception e)
                    {
                        if (e is NotImplementedException)
                        {
                            Error(405, "Method not allowed");
                        }
                        else
                        {
                            Error(e);
                        }
                    }
                    break;

                default:
                    Error(405, "Method not allowed");
                    break;
                }
                if (Response.IsClientConnected)
                {
                    Response.Write("", true);
                }
            }
            catch (Exception e)
            {
                Error(e);
            }
        }
Ejemplo n.º 4
0
        protected virtual void HandleError(HttpCwsContext context, int statusCode, string status, string customMessage)
        {
            context.Response.Clear();
            context.Response.ClearHeaders();
            context.Response.StatusCode        = statusCode;
            context.Response.StatusDescription = status;

            var content = string.Format("<H1>Error {0} <span>{1}</span></H1><P>{2}</P>",
                                        statusCode, status, customMessage);

            context.Response.Write(content, true);
        }
        /// <summary>
        /// Processes the CWS request.
        /// </summary>
        /// <param name="context">The context of the request.</param>
        void IHttpCwsHandler.ProcessRequest(HttpCwsContext context)
        {
            switch (context.Request.HttpMethod.ToUpper())
            {
            case "GET":
                ProcessGet(context);
                break;

            default:
                break;
            }
        }
Ejemplo n.º 6
0
            void IHttpCwsHandler.ProcessRequest(HttpCwsContext context)
            {
                try
                {
                    context.Response.ContentType = "application/json";
                    context.Response.AppendHeader("Access-Control-Allow-Origin", "*");
                    context.Response.AppendHeader("Access-Control-Allow-Headers", "Content-Type");
                    context.Response.AppendHeader("Access-Control-Allow-Methods", "GET, PUT, POST");
                    //CrestronConsole.PrintLine("HttpMethod: " + context.Request.HttpMethod);
                    //CrestronConsole.PrintLine("HttpPath: " + context.Request.Path);
                    //CrestronConsole.PrintLine("Httpname: " + context.Request.RouteData.Route.Name);
                    if (context.Request.Path.ToUpper() == "/CWS/API/" + this.slotNumber + "/CONFIGURATION/")
                    {
                        context.Response.StatusCode = 200;
                        switch (context.Request.HttpMethod)
                        {
                        case ("GET"):
                            Configuration.Reader();
                            context.Response.Write(JsonConvert.SerializeObject(Configuration.Obj), true);
                            break;

                        case ("PUT"):
                            string       JsonString;
                            StreamReader TheFile = new StreamReader(context.Request.InputStream);
                            JsonString = TheFile.ReadToEnd();
                            TheFile.Close();
                            //CrestronConsole.PrintLine("JsonString: " + JsonString);
                            Configuration.Obj = JsonConvert.DeserializeObject <RootObject>(JsonString);
                            Configuration.Writer();
                            context.Response.StatusCode = 204;
                            context.Response.Write(JsonConvert.SerializeObject(Configuration.Obj), true);
                            break;

                        default:
                            context.Response.StatusCode = 200;
                            context.Response.Write(JsonConvert.SerializeObject(GetApiHelp()), true);
                            break;
                        }
                    }
                    else
                    {
                        context.Response.StatusCode = 200;
                        context.Response.Write(JsonConvert.SerializeObject(GetApiHelp()), true);
                    }
                }
                catch (Exception ex)
                {
                    context.Response.ContentType = "text/html";
                    context.Response.StatusCode  = 401;
                    context.Response.Write(_Server.HtmlEncode(String.Format("<HTML><HEAD>ERROR</HEAD><BODY>The following error occurred: {0}. Stacktrace: {1}</BODY></HEAD></HTML>", ex.Message, ex.StackTrace)), true);
                }
            }
            public override void ProcessRequest(HttpCwsContext context)
            {
                string resourceUrl = "";
                int    rlyID;

                try
                {
                    resourceUrl = GetResourceUrl(context);
                    rlyID       = int.Parse((string)context.Request.RouteData.Values["id"]);
                }
                catch (Exception e)
                {
                    CrestronConsole.PrintLine("Error while parsing {id} of individual relay from URL: " + e.Message);
                    RespondWithJsonError(context, 404, "Not Found", resourceUrl, "The requested Relay ID does not parse as an integer");
                    return;
                }
                try
                {
                    string subID = context.Request.RouteData.Values["subid"].ToString();
                    if (server.sublists[rlyID].ContainsKey(subID))
                    {
                        if (context.Request.HttpMethod == "DELETE")
                        {
                            // remove the internal subscription resource
                            server.sublists[rlyID].Remove(subID);
                            CrestronConsole.PrintLine("subscription " + subID + " has been deleted by " + context.Request.UserHostAddress);
                            // send the response
                            context.Response.StatusCode        = 204;
                            context.Response.StatusDescription = "No Content";
                            context.Response.End();
                        }
                        else
                        {
                            RespondWithJsonError(context, 405, "Method Not Allowed", resourceUrl, "allowed methods: " + allowedMethods);
                        }
                    }
                    else
                    {
                        RespondWithJsonError(context, 404, "Not Found", resourceUrl, null);
                    }
                }
                catch (Exception e)
                {
                    CrestronConsole.PrintLine("Could not process request to " + context.Request.Url.AbsolutePath + ": " + e.Message);
                    RespondWithJsonError(context, 500, "Internal Server Error", resourceUrl, null);
                }
                finally
                {
                    CrestronConsole.PrintLine("Served response for " + context.Request.Url.AbsolutePath);
                }
            }
            // Write a Collection+JSON error message to the client. Put a non-empty string in msg to provide a specific
            // error description.
            public void RespondWithJsonError(HttpCwsContext context, int code, string title, string resourceUrl, string msg)
            {
                try
                {
                    context.Response.StatusCode        = code;
                    context.Response.StatusDescription = title;
                    context.Response.ContentType       = "application/vnd.collection+json";
                    if (code == 405)
                    {
                        context.Response.AppendHeader("Allow", allowedMethods);
                    }
                    // Since the client is expecting a Collection+JSON response, send the "error" object
                    // detailing the error
                    JObject err = new JObject
                    {
                        {
                            "collection", new JObject
                            {
                                { "version", "1.0" },
                                { "href", resourceUrl },
                                {
                                    "error", new JObject
                                    {
                                        { "title", title },
                                        { "code", code }
                                    }
                                }
                            }
                        }
                    };
                    // Optionally include a specific error message to the client. Automated clients
                    // would be able to print this message in an error log, for example
                    if (msg != null && msg != "")
                    {
                        err["collection"]["error"]["message"] = msg;
                    }

                    string json = JsonConvert.SerializeObject(err);
                    context.Response.Write(json, true);
                }
                catch (Exception e)
                {
                    CrestronConsole.PrintLine("Exception in RespondWithJsonError: " + e.Message);
                }
                finally
                {
                    CrestronConsole.PrintLine("Served a Collection+JSON error resposne");
                }
            }
            public override void ProcessRequest(HttpCwsContext context)
            {
                string resourceUrl = "";

                try
                {
                    resourceUrl = GetResourceUrl(context);
                    RespondWithJsonError(context, 404, "Not Found", resourceUrl, "Requested resource does not exist");
                }
                catch (Exception e)
                {
                    CrestronConsole.PrintLine("Error in DefaultHandler: " + e.Message);
                    RespondWithJsonError(context, 500, "Internal Server Error", resourceUrl, null);
                }
            }
Ejemplo n.º 10
0
        public void ProcessRequest(HttpCwsContext context)
        {
            var method = context.Request.HttpMethod;

            switch (method)
            {
            case "GET":
                context.Response.StatusCode  = 200;     // OK
                context.Response.ContentType = "application/json";

                var temp = new Dictionary <string, string>();

                if (context.Request.RouteData.Values.ContainsKey("NAME"))
                {
                    temp["name"] = context.Request.RouteData.Values["NAME"].ToString();
                    context.Response.Write(JsonConvert.SerializeObject(temp), true);
                }
                else
                {
                    temp["name"] = _name;
                    context.Response.Write(JsonConvert.SerializeObject(temp), true);
                }
                break;

            case "PUT":
                context.Response.StatusCode  = 200;     // OK
                context.Response.ContentType = "application/json";

                using (var reader = new StreamReader(context.Request.InputStream))
                {
                    var obj = JsonConvert.DeserializeObject <Dictionary <string, string> >(reader.ReadToEnd());

                    if (obj.ContainsKey("name"))
                    {
                        _name = obj["name"];
                        context.Response.Write("{ \"status\": \"OK\" }", true);
                    }
                }

                break;

            default:
                context.Response.StatusCode = 501;      // Not implemented
                context.Response.Write(
                    String.Format("{0} method not implemented!", method), true);
                break;
            }
        }
            public override void ProcessRequest(HttpCwsContext context)
            {
                string resourceUrl = "";

                try
                {
                    resourceUrl = GetResourceUrl(context);
                    if (context.Request.HttpMethod == "GET" || context.Request.HttpMethod == "HEAD") // HTTP methods are case-sensitive
                    {
                        context.Response.StatusCode        = 200;
                        context.Response.StatusDescription = "OK";
                        context.Response.AppendHeader("Content-Type", "application/vnd.collection+json");
                        context.Response.AppendHeader("Link", resourceUrl + "/web-hooks" + ", rel=\"Subscriptions\""); // requirement of RESTful WebHooks standard

                        if (context.Request.HttpMethod == "GET")                                                       // add the body for the GET request
                        {
                            // return the Collection+JSON representation of the Relay list

                            // Populate template.json with the Collection+JSON response.
                            // This response will not include the "template" property, since
                            // clients may not PUT or POST to the relay collection itself
                            string template = String.Copy(server.CjTemplate);
                            template = template.Replace("{@resource}", resourceUrl);
                            template = template.Replace("{@list}", FormatCollection(server.Relays, resourceUrl));
                            template = template.Replace("{@includetemplate}", "");
                            template = template.Replace("{@template}", "");
                            context.Response.Write(template, false); // write the populated template as a response
                        }

                        context.Response.End();
                    }
                    else
                    {
                        RespondWithJsonError(context, 405, "Method Not Allowed", resourceUrl, allowedMethods);
                    }
                }
                catch (Exception e)
                {
                    CrestronConsole.PrintLine("Could not process request to " +
                                              context.Request.Url.AbsolutePath + ": " + e.Message);
                    RespondWithJsonError(context, 500, "Internal Server Error", resourceUrl, null);
                }
                finally
                {
                    CrestronConsole.PrintLine("Served response for " + context.Request.Url.AbsolutePath);
                }
            }
            // Return a string representing the URL of the requested resource with no trailing
            // The returned URL won't end in a '/'
            public string GetResourceUrl(HttpCwsContext context)
            {
                // Constructing the URL from the HTTP request object avoids hard-coding the protocol (http/https)
                // into the URL, and it allows one to change the route name without breaking the code
                string resourceUrl = context.Request.Url.Scheme + "://"
                                     + context.Request.Url.Authority
                                     + context.Request.Url.AbsolutePath;

                // remove trailing '/'s if present
                resourceUrl = resourceUrl.TrimEnd('/');

                //while (resourceUrl.EndsWith("/"))
                //{
                //    resourceUrl = resourceUrl.Substring(0, resourceUrl.Length - 1);
                //}
                return(resourceUrl);
            }
Ejemplo n.º 13
0
        protected sealed override void HandleError(HttpCwsContext context, int statusCode, string status, string customMessage)
        {
            context.Response.Clear();
            context.Response.ClearHeaders();
            context.Response.ContentType       = "application/json";
            context.Response.StatusCode        = statusCode;
            context.Response.StatusDescription = status;

            var error = new
            {
                statusCode,
                status,
                message = customMessage
            };

            var data = JObject.FromObject(error);

            context.Response.Write(data.ToString(Formatting.Indented), true);
        }
            public override void ProcessRequest(HttpCwsContext context)
            {
                string resourceUrl = "";

                try
                {
                    resourceUrl = GetResourceUrl(context);
                    string subID = context.Request.RouteData.Values["subid"].ToString();
                    if (server.sublists[COLLECTION_SUBLIST].ContainsKey(subID))
                    {
                        if (context.Request.HttpMethod == "DELETE")
                        {
                            // remove the internal subscription resource
                            server.sublists[COLLECTION_SUBLIST].Remove(subID);
                            CrestronConsole.PrintLine("subscription " + subID + " has been deleted by " + context.Request.UserHostAddress);
                            // send the response
                            context.Response.StatusCode        = 204;
                            context.Response.StatusDescription = "No Content";
                            context.Response.End();
                        }
                        else
                        {
                            RespondWithJsonError(context, 405, "Method Not Allowed", resourceUrl, "allowed methods: " + allowedMethods);
                        }
                    }
                    else
                    {
                        RespondWithJsonError(context, 404, "Not Found", resourceUrl, null);
                    }
                }
                catch (Exception e)
                {
                    CrestronConsole.PrintLine("Could not process request to " + context.Request.Url.AbsolutePath + ": " + e.Message);
                    RespondWithJsonError(context, 500, "Internal Server Error", resourceUrl, null);
                }
                finally
                {
                    CrestronConsole.PrintLine("Served response for " + context.Request.Url.AbsolutePath);
                }
            }
        /// <summary>
        /// Processes a GET request.
        /// </summary>
        /// <param name="context">The context of the request.</param>
        private void ProcessGet(HttpCwsContext context)
        {
            Debug.WriteLine("Processing GET.");

            try
            {
                var html = string.Empty;
                var css  = string.Empty;
                using (var stream = Crestron.SimplSharp.Reflection.Assembly.GetExecutingAssembly().GetManifestResourceStream("Evands.Pellucid.Resources.CwsConsoleTemplate.html"))
                {
                    using (var reader = new Crestron.SimplSharp.CrestronIO.StreamReader(stream, true))
                    {
                        html = reader.ReadToEnd();
                    }
                }

                using (var stream = Crestron.SimplSharp.Reflection.Assembly.GetExecutingAssembly().GetManifestResourceStream("Evands.Pellucid.Resources.default.css"))
                {
                    using (var reader = new Crestron.SimplSharp.CrestronIO.StreamReader(stream, true))
                    {
                        css = reader.ReadToEnd();
                    }
                }

                context.Response.StatusCode = 200;
                var host     = context.Request.Url.Host;
                var protocol = useSecureWebsocket ? "wss://" : "ws://";
                html = html.Replace("{{ CSS }}", css).Replace("{{ PROTOCOL }}", protocol).Replace("{{ PORT }}", socketPort).Replace("{{ HOST }}", host);
                context.Response.Write(html, true);
            }
            catch (Exception ex)
            {
                Debug.WriteException(this, ex, "Exception while processing GET.");
                context.Response.StatusCode        = 500;
                context.Response.StatusDescription = string.Format("Internal Server Error - Exception encountered while retrieving Console Endpoint.<br/><br/>{0}", ex.ToString());
                context.Response.Write(context.Response.StatusDescription, true);
            }
        }
Ejemplo n.º 16
0
        void IHttpCwsHandler.ProcessRequest(HttpCwsContext context)
        {
            try
            {
                // handle requests
                if (context.Request.RouteData != null)
                {
                    switch (context.Request.RouteData.Route.Name.ToUpper())
                    {
                    case "ROOMNAME":
                        context.Response.StatusCode = 200;
                        context.Response.Write(InitialParametersClass.RoomName, true);
                        break;

                    default:
                        break;
                    }
                }
            }
            catch (Exception e)
            {
                ErrorLog.Error("CWS Handler: {0}", e.Message);
            }
        }
            public override void ProcessRequest(HttpCwsContext context)
            {
                uint   rlyID;
                string resourceUrl = "";

                try
                {
                    resourceUrl = GetResourceUrl(context);
                    rlyID       = uint.Parse((string)context.Request.RouteData.Values["id"]);
                }
                catch (Exception e)
                {
                    CrestronConsole.PrintLine("Error while parsing {id} of individual relay from URL: " + e.Message);
                    RespondWithJsonError(context, 404, "Not Found", resourceUrl, "The requested Relay ID does not parse as an integer");
                    return;
                }
                try
                {
                    if (rlyID >= 1 && rlyID <= server.NumberOfRelays)
                    {
                        context.Response.StatusCode        = 200;
                        context.Response.StatusDescription = "OK"; // server will respond with 200 OK for a successful GET, HEAD, or PUT
                        if (context.Request.HttpMethod == "GET" || context.Request.HttpMethod == "HEAD")
                        {
                            // add method-specific response headers
                            context.Response.AppendHeader("Content-Type", "application/vnd.collection+json");
                            context.Response.AppendHeader("Link", resourceUrl + "/web-hooks" + ", rel=\"Subscriptions\""); // requirement of RESTful WebHooks standard

                            if (context.Request.HttpMethod == "GET")                                                       // add the body for the GET request
                            {
                                // return the Collection+JSON representation of the individual Relay

                                // Populate template.json with the Collection+JSON response.
                                // This response will include the "template" property, since
                                // clients may PUT to the relay to update its state
                                string template = String.Copy(server.CjTemplate);
                                template = template.Replace("{@resource}", resourceUrl);
                                template = template.Replace("{@list}", FormatItem(server.Relays[rlyID], resourceUrl));
                                template = template.Replace("{@includetemplate}", ", \"template\": ");
                                template = template.Replace("{@template}", templateString);
                                context.Response.Write(template, false); // write the populated template as a response
                            }

                            context.Response.End();
                        }
                        else if (context.Request.HttpMethod == "PUT")
                        {
                            if (context.Request.Headers.Get("Content-Type") == "application/vnd.collection+json")
                            {
                                string json;
                                using (StreamReader s = new StreamReader(context.Request.InputStream))
                                {
                                    json = s.ReadToEnd();
                                }
                                JObject body = JsonConvert.DeserializeObject <JObject>(json);
                                if (body.IsValid(putRequestBodySchema))
                                {
                                    string state    = ((string)body["template"]["data"][0]["name"]).ToLower();
                                    string newValue = ((string)body["template"]["data"][0]["value"]).ToLower();
                                    if (state == "state" && (newValue == "close" || newValue == "open"))
                                    {
                                        // update internal Relay resource (true is Close, false is Open)
                                        server.Relays[rlyID].State = (newValue == "close") ? true : false; // the collection itself is 0-based, but the ID in the URL is 1-based

                                        // send the 200 OK response. No additional headers or entity-body is included in the
                                        // PUT response, but other applications may return a representation of the updated
                                        // resource
                                        context.Response.End();
                                    }
                                    else
                                    {
                                        RespondWithJsonError(context, 400, "Bad Request", resourceUrl, "Bad name or value property in Collection+JSON template");
                                    }
                                }
                                else
                                {
                                    RespondWithJsonError(context, 400, "Bad Request", resourceUrl, "malformed Collection+JSON template provided");
                                }
                            }
                            else
                            {
                                RespondWithJsonError(context, 415, "Unsupported Media Type", resourceUrl, "supported media types: " + supportedMediaTypes);
                            }
                        }
                        else
                        {
                            RespondWithJsonError(context, 405, "Method Not Allowed", resourceUrl, "allowed methods: " + allowedMethods);
                        }
                    }
                    else
                    {
                        RespondWithJsonError(context, 404, "Not Found", resourceUrl, "The requested relay ID does not map to an available relay");
                    }
                }
                catch (Exception e)
                {
                    CrestronConsole.PrintLine("Could not process request to " + context.Request.Url.AbsolutePath + ": " + e.Message);
                    RespondWithJsonError(context, 500, "Internal Server Error", resourceUrl, null);
                }
                finally
                {
                    CrestronConsole.PrintLine("Served response for " + context.Request.Url.AbsolutePath);
                }
            }
            public void ProcessRequest(HttpCwsContext context)
            {
                try
                {
                    // Only respond to POST requests made to the listen URL's path
                    if (parent.listenUrl.Path == context.Request.Url.AbsolutePath)
                    {
                        if (context.Request.HttpMethod == "POST")
                        {
                            // GET the individual relay to observe its updated state
                            HttpClientRequest req        = new HttpClientRequest();
                            string            linkString = context.Request.Headers["Link"];

                            // The notification POST request contains a link to the updated resource in the Link header.
                            // in compliance with the RESTful WebHooks standard at
                            // https://webhooks.pbworks.com/w/page/13385128/RESTful%20WebHooks
                            // This URL will be nested between the '<' and '>' characters,
                            // as described in https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Link
                            int    startIndex    = linkString.IndexOf('<') + 1;
                            int    endIndex      = linkString.IndexOf('>');
                            string linkUrlString = linkString.Substring(startIndex, endIndex - startIndex);

                            UrlParser relayUrl = new UrlParser(linkUrlString);
                            req.Url         = relayUrl;
                            req.RequestType = RequestType.Get;
                            HttpHeader acceptHeader = new HttpHeader("Accept", "application/vnd.collection+json");
                            req.Header.AddHeader(acceptHeader);
                            req.FinalizeHeader();
                            HttpClientResponse res = parent.client.Dispatch(req);

                            int    rlyID;
                            string newState = "";
                            if (res.Code == 200)
                            {
                                JObject item = JsonConvert.DeserializeObject <JObject>(res.ContentString);

                                rlyID    = (int)item["collection"]["items"][0]["data"][0]["value"];
                                newState = (string)item["collection"]["items"][0]["data"][1]["value"];
                            }
                            else
                            {
                                CrestronConsole.PrintLine("Failed to get individual relay");
                                return;
                            }
                            // log the notification message to console
                            CrestronConsole.PrintLine("NOTIFICATION: Relay #" + rlyID + "'s state changed to " + newState);

                            // respond to notification with 200 OK
                            context.Response.StatusCode        = 200;
                            context.Response.StatusDescription = "OK";
                            context.Response.End();
                        }
                        else
                        {
                            context.Response.StatusCode        = 405;
                            context.Response.StatusDescription = "Method Not Allowed";
                            context.Response.End();
                        }
                    }
                    else // ignore all other URLs besides the listener URL
                    {
                        CrestronConsole.PrintLine("Sending back a 404");
                        context.Response.StatusCode        = 404;
                        context.Response.StatusDescription = "Not Found";
                        context.Response.End();
                    }
                }
                catch (Exception e)
                {
                    try
                    {
                        // Respond with error message
                        context.Response.StatusCode        = 500;
                        context.Response.StatusDescription = "Internal Server Error";
                        context.Response.End();
                        CrestronConsole.PrintLine("Error in ProcessRequest: " + e.Message);
                    }
                    catch (Exception ex)
                    {
                        CrestronConsole.PrintLine("ProcessRequest unable to send error response: " + ex.Message);
                    }
                }
                finally
                {
                    ErrorLog.Notice("Served response to " + context.Request.UserHostName);
                }
            }
            public override void ProcessRequest(HttpCwsContext context)
            {
                // Example request/response:
                // =>
                // POST http://control-system/cws/api/relays/web-hooks
                // Content-Type : text/uri-list
                // Notification-Type : UPDATED
                //
                // http://www.webscripts.com/myaccount/mylistener
                //
                // <=
                // 201 Created
                // Location : http://control-system/cws/api/relays/web-hooks/46da87b3-7997-4ca1-8203-29ae68f01a6f
                // Link : <http://control-system/cws/api/relays/web-hooks>, rel="Subscriptions"
                string resourceUrl = "";
                int    rlyID;

                try
                {
                    resourceUrl = GetResourceUrl(context);
                    rlyID       = int.Parse((string)context.Request.RouteData.Values["id"]);
                }
                catch (Exception e)
                {
                    CrestronConsole.PrintLine("Error while parsing {id} of individual relay from URL: " + e.Message);
                    RespondWithJsonError(context, 404, "Not Found", resourceUrl, "The requested Relay ID does not parse as an integer");
                    return;
                }
                try
                {
                    if (context.Request.HttpMethod == "POST")
                    {
                        if (context.Request.Headers.Get("Content-Type") == "text/uri-list")
                        {
                            string callbackUrl;
                            using (StreamReader s = new StreamReader(context.Request.InputStream))
                            {
                                callbackUrl = s.ReadLine(); // the first line of the request's entity body must be the callback URL
                            }
                            if (context.Request.Headers.Get("Notification-Type") == "UPDATED")
                            {
                                // Create an internal subscription resource. Subscription constructor will validate the URL
                                // remove "/web-hooks" so the subscription is linked to the individual relay resource itself, not the webhook
                                Subscription newSub = new Subscription(resourceUrl.Replace("/web-hooks", ""), callbackUrl, "UPDATED", server.notifier);
                                server.sublists[rlyID].Add(newSub.SubID.ToString(), newSub);
                                CrestronConsole.PrintLine("Created new subscription resource with ID: " + newSub.SubID);
                                // send response
                                context.Response.StatusCode        = 201;
                                context.Response.StatusDescription = "Created";
                                context.Response.AppendHeader("Location", resourceUrl + "/" + newSub.SubID);
                                context.Response.AppendHeader("Link", "<" + resourceUrl + ">" + ", rel=\"Subscriptions\"");
                                context.Response.End();
                            }
                            // Other notification types include "ACCESSED," "CREATED," and "DELETED," but this
                            // server's WebHooks resources will not allow them
                            else
                            {
                                RespondWithJsonError(context, 400, "Bad Request", resourceUrl, "supported Notification-Types: UPDATED");
                            }
                        }
                        else
                        {
                            RespondWithJsonError(context, 415, "Unsupported Media Type", resourceUrl, "supported Content-Types: " + supportedMediaTypes);
                        }
                    }
                    else
                    {
                        RespondWithJsonError(context, 405, "Method Not Allowed", resourceUrl, "allowed methods: " + allowedMethods);
                    }
                }
                catch (System.UriFormatException e)
                {
                    CrestronConsole.PrintLine("Malformed client request to " + context.Request.Url.AbsolutePath + ": " + e.Message);
                    RespondWithJsonError(context, 400, "Bad Request", resourceUrl, "Malformed URL provided in request body");
                }
                catch (System.ArgumentNullException e)
                {
                    CrestronConsole.PrintLine("Malformed client request to " + context.Request.Url.AbsolutePath + ": " + e.Message);
                    RespondWithJsonError(context, 400, "Bad Request", resourceUrl, "No URL provided in request body");
                }
                catch (Exception e)
                {
                    CrestronConsole.PrintLine("Could not process request to " + context.Request.Url.AbsolutePath + ": " + e.Message);
                    RespondWithJsonError(context, 500, "Internal Server Error", resourceUrl, null);
                }
                finally
                {
                    CrestronConsole.PrintLine("Served response for " + context.Request.Url.AbsolutePath);
                }
            }
Ejemplo n.º 20
0
 /// <summary>
 /// Provides processing of HTTP requests by a HttpHandler that implements
 ///                 the <see cref="T:Crestron.SimplSharp.WebScripting.IHttpCwsHandler"/> interface.
 /// </summary>
 /// <param name="context">The object encapsulating the HTTP request.</param>
 /// <returns>
 /// true is the request was processed successfully; otherwise, false.
 /// </returns>
 public override void ProcessRequest(HttpCwsContext context)
 {
     context.Response.ContentType = "application/json";
     base.ProcessRequest(context);
 }
Ejemplo n.º 21
0
        public void ProcessRequest(HttpCwsContext context)
        {
            try
            {
                Uri    requestUri = context.Request.Url;
                string method     = context.Request.HttpMethod;
                string path       = context.Request.Path.ToLower();
                switch (path)
                {
                case "/cws/":
                    if (method == "GET" || method == "HEAD")
                    {
                        context.Response.StatusCode        = 200;
                        context.Response.StatusDescription = "OK";
                        context.Response.ContentType       = "text/html";
                        // include the body for the GET request, but not HEAD
                        if (method == "GET")
                        {
                            context.Response.Write(CreateHtmlBody(startHtml,
                                                                  // Use the current state to decide whether to enable the buttons or not
                                                                  new NameValueCollection()
                            {
                                { "enable",
                                  Registered ? "" : "disabled" },
                                { "enable-forget-access",
                                  (Registered && hasAccessToken) ? "" : "disabled" },
                                { "enable-forget-refresh",
                                  (Registered && HasRefreshToken) ? "" : "disabled" }
                            }),
                                                   false);
                        }
                        context.Response.End();
                    }
                    else
                    {
                        SendError(context, 405, context.Request.HttpMethod + " not allowed", "GET", "HEAD");
                    }
                    break;

                case "/cws/register":
                    if (method == "GET" || method == "HEAD")
                    {
                        context.Response.StatusCode        = 200;
                        context.Response.StatusDescription = "OK";
                        context.Response.ContentType       = "text/html";
                        // include the body for the GET request, but not HEAD
                        if (method == "GET")
                        {
                            string body = Registered ? File.ReadToEnd(registeredHtml, Encoding.UTF8) :
                                          File.ReadToEnd(unregisteredHtml, Encoding.UTF8);

                            body = CreateHtmlBody(registerHtml,
                                                  new NameValueCollection()
                            {
                                { "register", body }
                            });
                            if (!Registered)
                            {
                                // Make two additional variable evaluations on the "unregistered" HTML page
                                string scheme = context.Request.Url.Scheme;
                                body = body.Replace("{@callbackUrl}", CallbackUrl);
                                body = body.Replace("{@httpsAlert}", (scheme == "https") ? "" :
                                                    "<p>WARNING: It looks like you got here via http, not https."
                                                    + " Check that SSL is enabled"
                                                    + " on the control system. Don't submit anything until it is!</p>");
                            }
                            context.Response.Write(body, false);
                        }
                        context.Response.End();
                    }
                    else if (method == "POST")
                    {
                        // Get the entity-body, which should contain the domain, client_id, and client_secret
                        // parameters
                        if (context.Request.ContentType != "application/x-www-form-urlencoded")
                        {
                            SendError(context, 415, "Content-Type must be application/x-www-form-urlencoded");
                            return;
                        }
                        // POST requests from HTML forms put their parameters in the request body
                        // using the application/x-www-form-urlencoded content type. An example can be found
                        // at https://developer.mozilla.org/en-US/docs/Web/HTTP/Methods/POST
                        string requestBody;
                        // Parse the entity-body of the request and check for correctness
                        using (StreamReader sr = new StreamReader(context.Request.InputStream))
                        {
                            requestBody = sr.ReadToEnd();
                        }
                        NameValueCollection keyValuePairs = ParseQueryParams(requestBody);

                        string[] keys = keyValuePairs.AllKeys;

                        // Handler for the "Unregister and Return to Home Page" button
                        if (keys.Contains("unregister"))
                        {
                            Registered = false;
                            context.Response.Redirect("/cws/", true);
                            return;
                        }

                        // Check that all necessary registration fields (client_id, client_secret, and domain)
                        // have been provided
                        if (String.IsNullOrEmpty(keyValuePairs["domain"]) ||
                            String.IsNullOrEmpty(keyValuePairs["client_id"]) ||
                            String.IsNullOrEmpty(keyValuePairs["client_secret"]))
                        {
                            // Error, bad request
                            SendError(context, 400, "Registration submission is missing a necessary field");
                            return;
                        }
                        // Save the values provided to the datastore
                        Domain       = keyValuePairs["domain"];
                        ClientID     = keyValuePairs["client_id"];
                        ClientSecret = keyValuePairs["client_secret"];

                        // Send OK response
                        context.Response.StatusCode        = 200;
                        context.Response.StatusDescription = statusDescriptions[200];
                        context.Response.Write(CreateHtmlBody(regsuccessHtml,
                                                              new NameValueCollection()
                        {
                            { "domain", Domain },
                            { "client_id", ClientID }
                        }), true);

                        // Now the client is registered with the Authorization Server
                        Registered = true;
                    }
                    else
                    {
                        SendError(context, 405, context.Request.HttpMethod + " not allowed", "GET", "HEAD", "POST");
                    }
                    break;

                case "/cws/authorize":
                    if (!Registered)
                    {
                        SendError(context, 404, "The client must be registered with the Auth0 Authorization server" +
                                  " before it can get authorized");
                        return;
                    }
                    if (method == "GET" || method == "HEAD")
                    {
                        // First, discard the old set of tokens
                        accessToken     = Empty;
                        hasAccessToken  = false;
                        RefreshToken    = Empty;
                        HasRefreshToken = false;

                        // Generate a random state parameter, which the callback URL will check for
                        // consistency
                        stateString = Guid.NewGuid().ToString("N");
                        NameValueCollection queries =
                            new NameValueCollection()
                        {
                            // necessary scopes to get full user info and to get a Refresh Token
                            { "scope", "offline_access%20openid%20email%20profile" },
                            // Authorization code flow
                            { "response_type", "code" },
                            { "client_id", ClientID },
                            { "redirect_uri", CallbackUrl },
                            { "state", stateString },
                            // Always show the login and consent pages upon redirecting
                            { "prompt", "login%20consent" }
                        };

                        context.Response.StatusCode        = 302;
                        context.Response.StatusDescription = statusDescriptions[302];
                        // Contruct the redirect URL and send the user to Auth0's authorization endpoint
                        context.Response.AppendHeader("Location", BuildAuthorizationUrl(queries));
                        context.Response.End();
                    }
                    else
                    {
                        SendError(context, 405, context.Request.HttpMethod + " not allowed", "GET", "HEAD");
                    }
                    break;

                case "/cws/callback":
                    if (method == "HEAD" || method == "GET")
                    {
                        context.Response.StatusCode        = 200;
                        context.Response.StatusDescription = statusDescriptions[200];
                        if (method == "GET")
                        {
                            // Check if there's a query string
                            if (context.Request.Url.Query == null ||
                                context.Request.Url.Query == "")
                            {
                                SendError(context, 400, "No Query parameters provided");
                                return;
                            }
                            NameValueCollection queryParams = null;
                            // Parse query string and check state
                            try
                            {
                                queryParams = ParseQueryParams(context.Request.Url.Query);
                            }
                            catch (Exception e)
                            {
                                SendError(context, 400, "Query string parsing error: " + e.Message);
                                return;
                            }
                            if (queryParams["state"] != stateString)
                            {
                                CrestronConsole.PrintLine("State parameter mismatch: expected " +
                                                          stateString + " but got " + queryParams["state"]);
                                SendError(context, 400, "State parameter did not match.");
                                return;
                            }
                            authorizationCode = queryParams["code"];

                            if (String.IsNullOrEmpty(authorizationCode))
                            {
                                // Authorization was denied by the user
                                SendError(context, 400,
                                          "Authorization was denied. The OAuth Client has no Access or Refresh token now");
                                return;
                            }

                            // Using an HttpsClient, exchange the received authorization code for an Access Token
                            using (HttpsClient client = new HttpsClient())
                            {
                                HttpsClientRequest req = new HttpsClientRequest();
                                req.RequestType = Crestron.SimplSharp.Net.Https.RequestType.Post;
                                req.Url         = new UrlParser(TokenEndpoint);
                                CrestronConsole.PrintLine("GETting {0}", req.Url);
                                HttpsHeaders headers = new HttpsHeaders();
                                // Auth0's token endpoint expects all the necessary information to be
                                // placed in the entity-body of the request
                                headers.SetHeaderValue("Content-Type", "application/x-www-form-urlencoded");

                                req.ContentString = BuildQueryString(
                                    new NameValueCollection
                                {
                                    { "grant_type", "authorization_code" },
                                    { "client_id", ClientID },
                                    { "client_secret", ClientSecret },
                                    { "code", authorizationCode },
                                    { "redirect_uri", CallbackUrl }
                                });

                                // Always set the Content-Length of your POST request to indicate the length of the body,
                                // or else the Content-Length will be set to 0 by default!
                                headers.SetHeaderValue("Content-Length", req.ContentString.Length.ToString());
                                req.Header = headers;

                                // Send the POST request to the token endpoint and wait for a response...
                                HttpsClientResponse tokenResponse = client.Dispatch(req);
                                if (tokenResponse.Code >= 200 && tokenResponse.Code < 300)
                                {
                                    // Parse JSON response and securely store the tokens
                                    JObject resBody = JsonConvert.DeserializeObject <JObject>(tokenResponse.ContentString);
                                    accessToken     = (string)resBody["access_token"];
                                    hasAccessToken  = true;
                                    RefreshToken    = (string)resBody["refresh_token"];
                                    HasRefreshToken = true;
                                    CrestronConsole.PrintLine("Received \"{0}\" Access/Refresh Tokens. They expire in {1} hours",
                                                              (string)resBody["token_type"],
                                                              (int)resBody["expires_in"] / 60.0 / 60.0);
                                    // Respond
                                    context.Response.Write(CreateHtmlBody(authsuccessHtml, null), false);
                                }
                                else
                                {
                                    SendError(context, tokenResponse.Code,
                                              "Could not get access/refresh tokens. Token endpoint returned code " +
                                              "<strong>" + tokenResponse.Code + "</strong>" +
                                              "<br /><br />Error Message:<br /><br /><strong>"
                                              + tokenResponse.ContentString + "</strong>");
                                    return;
                                }
                            }
                        }
                        context.Response.End();
                    }
                    else
                    {
                        SendError(context, 405, context.Request.HttpMethod + " not allowed", "GET", "HEAD");
                    }
                    break;

                case "/cws/test":
                    if (method == "GET" || method == "HEAD")
                    {
                        if (method == "GET")
                        {
                            if (!Registered)
                            {
                                SendError(context, 404, "The client must be registered before it can try to access" +
                                          " a protected resource");
                                return;
                            }

                            // Send a GET request to the protected resource
                            using (HttpsClient client = new HttpsClient())
                            {
                                HttpsClientRequest req = new HttpsClientRequest();
                                req.RequestType = Crestron.SimplSharp.Net.Https.RequestType.Get;
                                req.Url         = new UrlParser(ResourceEndpoint);
                                CrestronConsole.PrintLine("GETting {0}", req.Url);
                                // Put the Access Token in the Authorization header, if it's present
                                if (hasAccessToken)
                                {
                                    req.Header.SetHeaderValue("Authorization", "Bearer " + accessToken);
                                }
                                var res = client.Dispatch(req);
                                if (res.Code >= 200 && res.Code < 300)
                                {
                                    JObject resBody =
                                        JsonConvert.DeserializeObject <JObject>(res.ContentString);
                                    string name, email, picUrl;
                                    bool   verified;
                                    // Try to get the username from any of these three JSON properties,
                                    // if they are defined. If none of them are defined, put "undefined" as a
                                    // placeholder name
                                    name = (string)resBody["given_name"] ??
                                           (string)resBody["nickname"] ??
                                           (string)resBody["email"] ??
                                           "undefined";
                                    email    = (string)resBody["email"] ?? "undefined";
                                    picUrl   = (string)resBody["picture"] ?? "undefined";
                                    verified = (bool?)resBody["email_verified"] ?? false;

                                    context.Response.Write(CreateHtmlBody(testHtml,
                                                                          new NameValueCollection()
                                    {
                                        { "name", name },
                                        { "email", email },
                                        { "verified", "<strong>" + (verified ? "verified" : "not verified")
                                          + "</strong>" },
                                        { "pic_url", picUrl },
                                    }), false);
                                }
                                else
                                {
                                    // If RefreshAccessToken succeeds, accessToken will contain the new token
                                    // If not, display the body of the error response returned from the
                                    // authorization server
                                    string errMsg;
                                    int    errCode;
                                    if (RefreshAccessToken(out errMsg, out errCode))
                                    {
                                        CrestronConsole.PrintLine("Successfully refreshed the Access Token." +
                                                                  " Redirecting user to /cws/Test...");
                                        context.Response.Redirect("/cws/Test", true);
                                        return;
                                    }
                                    else
                                    {
                                        SendError(context, errCode,
                                                  "Failed to refresh Access Token." +
                                                  " Resource endpoint returned code <strong>" + errCode + "</strong>" +
                                                  "<br /><br />Error Message:<br /><br /><strong>" + errMsg + "</strong>");
                                        return;
                                    }
                                }
                                context.Response.End();
                            }
                        }
                    }
                    else
                    {
                        SendError(context, 405, context.Request.HttpMethod + " not allowed", "GET", "HEAD");
                    }
                    break;

                case "/cws/forgetaccess":
                    if (method == "GET" || method == "HEAD")
                    {
                        context.Response.StatusCode        = 200;
                        context.Response.StatusDescription = statusDescriptions[200];
                        if (method == "GET")
                        {
                            if (hasAccessToken)
                            {
                                accessToken    = Empty;
                                hasAccessToken = false;
                                context.Response.Write(CreateHtmlBody(tokenDisposedHtml,
                                                                      new NameValueCollection
                                {
                                    { "token_kind", "Access" }
                                }), false);
                            }
                            else
                            {
                                SendError(context, 404, "There is currently no Access Token to be disposed of");
                            }
                        }
                        context.Response.End();
                    }
                    else
                    {
                        SendError(context, 405, context.Request.HttpMethod + " not allowed", "GET", "HEAD");
                    }
                    break;

                case "/cws/forgetrefresh":
                    if (method == "GET" || method == "HEAD")
                    {
                        context.Response.StatusCode        = 200;
                        context.Response.StatusDescription = statusDescriptions[200];
                        if (method == "GET")
                        {
                            if (HasRefreshToken)
                            {
                                RefreshToken    = Empty;
                                HasRefreshToken = false;
                                context.Response.Write(CreateHtmlBody(tokenDisposedHtml,
                                                                      new NameValueCollection
                                {
                                    { "token_kind", "Refresh" }
                                }), false);
                            }
                            else
                            {
                                SendError(context, 404, "There is currently no Refresh Token to be disposed of");
                            }
                        }
                        context.Response.End();
                    }
                    else
                    {
                        SendError(context, 405, context.Request.HttpMethod + " not allowed", "GET", "HEAD");
                    }
                    break;

                default:
                    SendError(context, 404, path + " not found");
                    break;
                }
            }
            catch (Exception e)
            {
                CrestronConsole.PrintLine("Error in ProcessRequest(): {0}", e);
                try
                {
                    SendError(context, 500, "An error occurred in the CWS server: " + e.Message);
                    CrestronConsole.PrintLine("Sent " + context.Response.StatusCode +
                                              " response to " + context.Request.UserHostName);
                }
                catch (Exception ex)
                {
                    CrestronConsole.PrintLine("Could not send Error response: {0}", ex);
                }
            }
            finally
            {
                CrestronConsole.PrintLine("Sent " + context.Response.StatusCode +
                                          " response to " + context.Request.UserHostName);
            }
        }
Ejemplo n.º 22
0
        public void ProcessRequest(HttpCwsContext context)
        {
            var method = context.Request.HttpMethod;

            switch (method)
            {
            case "GET":
                context.Response.StatusCode  = 200;     // OK
                context.Response.ContentType = "application/json";

                if (context.Request.RouteData.Values.ContainsKey("PROPERTY"))
                {
                    var prop = context.Request.RouteData.Values["PROPERTY"];
                    context.Response.Write(GetPropertyJSON(prop.ToString()), true);
                }
                else
                {
                    try
                    {
                        context.Response.Write(JsonConvert.SerializeObject(_settings), true);
                    }
                    catch (Exception e)
                    {
                        ErrorLog.Error("Exception in RoomRequest.ProcessRequest: {0}",
                                       e.Message);
                    }
                }

                break;

            case "PUT":
                context.Response.StatusCode  = 200;     // OK
                context.Response.ContentType = "application/json";

                SystemSettings newSettings;

                try
                {
                    using (var reader = new StreamReader(context.Request.InputStream))
                    {
                        newSettings = JsonConvert.DeserializeObject <SystemSettings>
                                          (reader.ReadToEnd());

                        CrestronConsole.PrintLine("Inputs: {0}", newSettings.inputs.Length);
                        CrestronConsole.PrintLine("Outputs: {0}", newSettings.outputs.Length);
                    }

                    _settings.Copy(newSettings);
                }
                catch (Exception e)
                {
                    ErrorLog.Error("Exception in RoomRequest.ProcessRequest: {0}",
                                   e.Message);
                }

                context.Response.Write("{ \"status\": \"OK\" }", true);
                break;

            default:
                context.Response.StatusCode = 501;      // Not implemented
                context.Response.Write(
                    String.Format("{0} method not implemented!", method),
                    true);
                break;
            }
        }
 protected RestfulRelayServer server;  // reference to the server, the handler's "parent"
 public abstract void ProcessRequest(HttpCwsContext context);