Пример #1
0
        /// <summary>
        /// Converts an object to an HTTP response message body.
        /// content may be null.
        /// If the content is null, the string "null" is produced as
        /// its representation. Otherwise, the object's ToString
        /// method is called for producing the representation.
        /// Preconditions
        ///     context != null
        /// Postconditions
        ///     "context.RequestContent contains serialized representation of
        ///      content object"
        ///     context.ResponseContentType == "text/plain"
        /// </summary>
        public static void Serialize(RequestHandlerContext context,
                                     object content)
        {
            string s = (content != null) ? content.ToString() : "null";

            context.SetResponse(s, "text/plain");
        }
        public void HandleRequest(RequestHandlerContext context)
        {
            Contract.Requires(context != null);
            if (!IsOpen)
            {
                Open();
            }

            context.ResponseMaxAge = 0;         // no caching (default is -1, i.e., no cache header)
            var s = "";
            // Service Uptime
            TimeSpan delta = Diagnostics.ServiceUptime;

            s = s + "Service Uptime\t" + delta + "\r\n";
            // accept errors (e.g., timeouts)
            s = s + "Accept Errors\t" + Diagnostics.AcceptErrors + "\r\n";
            // accept failures (unknown exceptions)
            s = s + "Accept Failures\t" + Diagnostics.AcceptFailures + "\r\n";
            // requests total
            s = s + "Requests Total\t" + Diagnostics.RequestsTotal + "\r\n";
            // request handler errors (e.g., timeouts)
            s = s + "Request Handler Errors\t" + Diagnostics.RequestHandlerErrors + "\r\n";
            // request handler failures (unknown exceptions)
            s = s + "Request Handler Failures\t" + Diagnostics.RequestHandlerFailures + "\r\n";
            // free memory
            s = s + "Available Heap Space\t" + Debug.GC(true) + "\r\n";
            context.SetResponse(s, "text/plain");
        }
Пример #3
0
        static void HandleOn(RequestHandlerContext context)
        {
            lightWrite(true);
            string s = "<h1>ON " + DateTime.Now.ToString();

            context.SetResponse(s, "text/html");
        }
Пример #4
0
 /// <summary>
 /// Interprets an HTTP request and produces an appropriate HTTP
 /// response.
 /// If the manipulated variable is not open, Open is called first.
 /// Preconditions
 ///     context != null
 /// </summary>
 /// <param name="context">Provides access to the received request,
 /// the server, and to the (empty) response.</param>
 public void HandleRequest(RequestHandlerContext context)
 {
     Contract.Requires(context != null);
     if (!initialized)
     {
         Open();
     }
     if (context.RequestMethod == "PUT")
     {
         object setpoint;
         if (FromHttpRequest(context, out setpoint))
         {
             // setpoint may be null
             ToActuator(setpoint);
             lastSetpoint = setpoint;
             context.ResponseStatusCode = 200;    // OK
         }
         else
         {
             context.ResponseStatusCode = 400;    // Bad Request
         }
     }
     else if (context.RequestMethod == "GET")
     {
         // lastSetpoint may be null
         ToHttpResponse(context, lastSetpoint);
         context.ResponseStatusCode = 200;    // OK
     }
     else
     {
         context.ResponseStatusCode = 405;    // Method Not Allowed
     }
 }
Пример #5
0
 static void HandleLedTargetHtml(RequestHandlerContext context)
 {
     string requestUri = context.BuildRequestUri("/led/target");
     var script =
         @"<html>
             <head>
               <script type=""text/javascript"">
                 var r;
                 try {
                   r = new XMLHttpRequest();
                 } catch (e) {
                   r = new ActiveXObject('Microsoft.XMLHTTP');
                 }
                 function put (content) {
                   r.open('PUT', '" + requestUri + @"');
                   r.setRequestHeader('Content-Type', 'text/plain');
                   r.send(content);
                 }
               </script>
             </head>
             <body>
               <p>
                 <input type=""button"" value=""Switch LED on""
                   onclick=""put('true')""/>
                 <input type=""button"" value=""Switch LED off""
                   onclick=""put('false')""/>
                 <input type=""button"" value=""Bah""
                   onclick=""put('bah')""/>
               </p>
             </body>
          </html>";
     context.SetResponse(script, "text/html");
 }
Пример #6
0
 static void HandleBlinkTargetHtml(RequestHandlerContext context)
 {
     string requestUri =
         context.BuildRequestUri("/blinkingPeriod/target");
     var script =
         @"<html>
             <head>
               <script type=""text/javascript"">
                 var r;
                 try {
                   r = new XMLHttpRequest();
                 } catch (e) {
                   r = new ActiveXObject('Microsoft.XMLHTTP');
                 }
                 function put (content) {
                   r.open('PUT', '" + requestUri + @"');
                   r.setRequestHeader(""Content-Type"", ""text/plain"");
                   r.send(document.getElementById(""period"").value);
                 }
               </script>
             </head>
             <body>
               <p>
                 <input type=""text"" value=""500"" id=""period"">
                 <input
                   type=""button"" value=""Set"" onclick=""put()""/>
               </p>
             </body>
           </html>";
     context.SetResponse(script, "text/html");
 }
Пример #7
0
        /// <summary>
        /// Converts an HTTP request message body to a double object.
        /// content is not null if conversion was successful.
        /// The return value indicates whether conversion was successful.
        /// Preconditions
        ///     context != null
        /// Postconditions
        ///     Result =>
        ///         content != null
        ///         content is double
        ///         "content contains deserialized representation of
        ///          context.RequestContent"
        ///     !Result =>
        ///         content == null
        ///         "context.RequestContent could not be converted to a
        ///          C# object"
        /// </summary>
        public static bool TryDeserializeDouble(RequestHandlerContext context,
                                                out object content)
        {
            string s          = context.RequestContent;
            double x          = 0;
            int    decimalDiv = 0;

            content = null;
            foreach (char c in s)
            {
                if ((c == '.') && (decimalDiv == 0))
                {
                    decimalDiv = 1;
                }
                else if ((c < '0') || (c > '9'))
                {
                    return(false);
                }
                else
                {
                    x          = x * 10;
                    decimalDiv = decimalDiv * 10;
                    x          = x + (int)(c - '0');
                }
            }
            if (decimalDiv != 0)
            {
                x = x / decimalDiv;
            }
            content = x;
            return(true);
        }
 /// <summary>
 /// Converts an HTTP request message body to a bool object.
 /// content is not null if conversion was successful.
 /// The return value indicates whether conversion was successful.
 /// Preconditions
 ///     context != null
 /// Postconditions
 ///     Result =>
 ///         content != null
 ///         content is bool
 ///         "content contains deserialized representation of
 ///          context.RequestContent"
 ///     !Result =>
 ///         content == null
 ///         "context.RequestContent could not be converted to a
 ///          C# object"
 /// </summary>
 public static bool TryDeserializeBool(
     RequestHandlerContext context, out object content)
 {
     string s = context.RequestContent;
     if (s == "true") { content = true; return true; }
     else if (s == "false") { content = false; return true; }
     else { content = null; return false; }
 }
Пример #9
0
 static void HandleGetAboutHtml(RequestHandlerContext context)
 {
     string s =
         "<html>\r\n" +
         "\t<body>\r\n" +
         "\t\t<h1>About</h1>\r\n" +
         "\t\t<p>This is a Netduino Plus 2 running .net Micro Framework</p>\r\n" +
         "\t</body>\r\n" +
         "</html>";
     context.SetResponse(s, "text/html");
 }
Пример #10
0
 static void HandleGetHelloHtml(RequestHandlerContext context)
 {
     string s =
         "<html>\r\n" +
         "\t<body>\r\n" +
         "\t\tHello <strong>Web</strong> at " +
             DateTime.Now + "\r\n" +
         "\t</body>\r\n" +
         "</html>";
     context.SetResponse(s, "text/html");
 }
Пример #11
0
        /// <summary>
        /// Interprets an HTTP request and produces an appropriate HTTP
        /// response.
        /// If the measured variable is not open, Open is called first.
        /// Preconditions
        ///     context != null
        /// </summary>
        /// <param name="context">Provides access to the received request,
        /// the server, and to the (empty) response.</param>
        public void HandleRequest(RequestHandlerContext context)
        {
            Contract.Requires(context != null);
            if (!initialized)
            {
                Open();
            }

            context.ResponseMaxAge = 0;         // no caching (default is -1, i.e., no cache header)
            object sample = FromSensor();

            // sample may be null
            ToHttpResponse(context, sample);
        }
Пример #12
0
    static void HandleHello(RequestHandlerContext context)
    {
        onboardLedBlink = !onboardLedBlink;

        var a1Uri = "/" + context.RequestUri.Split('/')[1] + "/a1";
        var d12Uri = "/" + context.RequestUri.Split('/')[1] + "/d12";

        string s = "<h1>Hello via Relay<h2>Led Blink is " + onboardLedBlink.ToString() + "<p> RequestUri is: " + context.RequestUri + "<p> Try <a href='" + a1Uri + "'>Analog Input A1</a> and <a href='" + d12Uri + "'>Digital Input D12</a> for sensors as well<p> PUT to /d13 for led Actuator on Pin 13!";

        s = s + "<p> use a PUT generator like <a href='http://www.hurl.it/hurls/90adc685db37c71ccb9576b0d115fbc8809faa1c/aea0240d19dc34535db35a9e64ed00b195d3bb53'>this to turn off,</a>";
        s = s + "<p> or like <a href='http://www.hurl.it/hurls/1bf8d43ca68c6a17ebdf77409c437031fe21d8e5/76fe79f73b808d69dddbb8caffd070ee9e90137b'>this to turn on.</a>";
        s = s + "<p>In order to use this fuctionality in a trigger to D11 from Xively you must create POST requests for <a href='http://www.hurl.it/hurls/3703de296f48844bef801e59e3486229e805f462/f5b7a99f9e6ec038f0196f4945f539ebbbdcc9cb#'>on</a> and <a href='http://www.hurl.it/hurls/8a8463b4d5900d51fe8a34cbf4d51d20ebd16c50/3211ff2d1b035f914f9af5431f5e133c5b1d5001'>off</a>.";

        context.SetResponse(s, "text/html");
    }
Пример #13
0
        /// <summary>
        /// Converts an HTTP request message body to an int object.
        /// content is not null if conversion was successful.
        /// The return value indicates whether conversion was successful.
        /// Preconditions
        ///     context != null
        /// Postconditions
        ///     Result =>
        ///         content != null
        ///         content is int
        ///         "content contains deserialized representation of
        ///          context.RequestContent"
        ///     !Result =>
        ///         content == null
        ///         "context.RequestContent could not be converted to a
        ///          C# object"
        /// </summary>
        public static bool TryDeserializeInt(RequestHandlerContext context,
                                             out object content)
        {
            string s = context.RequestContent;
            int    x;

            if (Utilities.TryParseUInt32(s, out x))
            {
                content = x;
                return(true);
            }
            else
            {
                content = null;
                return(false);
            }
        }
Пример #14
0
        /// <summary>
        /// Converts an HTTP request message body to a bool object.
        /// content is not null if conversion was successful.
        /// The return value indicates whether conversion was successful.
        /// Preconditions
        ///     context != null
        /// Postconditions
        ///     Result =>
        ///         content != null
        ///         content is bool
        ///         "content contains deserialized representation of
        ///          context.RequestContent"
        ///     !Result =>
        ///         content == null
        ///         "context.RequestContent could not be converted to a
        ///          C# object"
        /// </summary>
        public static bool TryDeserializeBool(
            RequestHandlerContext context, out object content)
        {
            string s = context.RequestContent;

            if (s == "true")
            {
                content = true; return(true);
            }
            else if (s == "false")
            {
                content = false; return(true);
            }
            else
            {
                content = null; return(false);
            }
        }
        public void HandleRequest(RequestHandlerContext context)
        {
            Contract.Requires(context != null);
            if (!IsOpen) { Open(); }

            context.ResponseMaxAge = 0;         // no caching (default is -1, i.e., no cache header)
            var s = "";
            // Service Uptime
            TimeSpan delta = Diagnostics.ServiceUptime;
            s = s + "Service Uptime\t" + delta + "\r\n";
            // accept errors (e.g., timeouts)
            s = s + "Accept Errors\t" + Diagnostics.AcceptErrors + "\r\n";
            // accept failures (unknown exceptions)
            s = s + "Accept Failures\t" + Diagnostics.AcceptFailures + "\r\n";
            // requests total
            s = s + "Requests Total\t" + Diagnostics.RequestsTotal + "\r\n";
            // request handler errors (e.g., timeouts)
            s = s + "Request Handler Errors\t" + Diagnostics.RequestHandlerErrors + "\r\n";
            // request handler failures (unknown exceptions)
            s = s + "Request Handler Failures\t" + Diagnostics.RequestHandlerFailures + "\r\n";
            // free memory
            s = s + "Available Heap Space\t" + Debug.GC(true) + "\r\n";
            context.SetResponse(s, "text/plain");
        }
Пример #16
0
        static void HandleTemp(RequestHandlerContext context)
        {
            string s = "<h1>Temp " + voltagePort.Read().ToString();

            context.SetResponse(s, "text/html");
        }
Пример #17
0
        static void HandleToggle(RequestHandlerContext context)
        {
            lightWrite(!lOn);
            string s = "<h1>Toggle -- was on: " +(!lOn).ToString() + " " + DateTime.Now.ToString();

            context.SetResponse(s, "text/html");
        }
Пример #18
0
        /// <summary>
        /// Private method that handles an incoming request.
        /// It sets up a RequestHandlerContext instance with the data from
        /// the incoming HTTP request, finds a suitable request handler to
        /// produce the response, and then sends the response as an HTTP
        /// response back to the client.
        /// Preconditions
        ///     "connection is open"
        ///     serviceRoot != null
        ///     serviceRoot.Length > 8
        ///     "serviceRoot starts with 'http://' and ends with '/'"
        ///     requestRouting != null
        /// </summary>
        /// <param name="connection">Open TCP/IP connection</param>
        /// <param name="serviceRoot">The absolute URI that is a prefix of
        /// all request URIs that this web service supports. It must start
        /// with "http://" and must end with "/".</param>
        /// <param name="relayDomain">Host name or Internet address of the
        /// relay to be used, or null if no relay is used</param>
        /// <param name="requestRouting">Collection of
        ///   { request pattern, request handler}
        /// pairs</param>
        /// <param name="connectionClose">Return parameter that indicates
        /// that the connection should be closed after this call. This may
        /// be because the incoming request has a "Connection: close"
        /// header, because the request handler has set the
        /// ConnectionClose property, or because some error occurred.
        /// </param>
        internal static void ConsumeRequest(Stream connection,
                                            string serviceRoot, string relayDomain,
                                            RequestRouting requestRouting,
                                            ref bool connectionClose)
        {
            Contract.Requires(connection != null);
            Contract.Requires(serviceRoot != null);
            Contract.Requires(serviceRoot.Length > 8);
            Contract.Requires(serviceRoot.Substring(0, 7) == "http://");
            Contract.Requires(serviceRoot[serviceRoot.Length - 1] != '/');
            Contract.Requires(requestRouting != null);

            // initialization --------------------------------------------
            HttpReader reader  = new HttpReader();
            HttpWriter writer  = new HttpWriter();
            var        context = new RequestHandlerContext(serviceRoot,
                                                           relayDomain);

            // Both client and server may request closing the connection.
            // Initially, we assume that neither one wants to close the
            // connection.
            context.ConnectionClose = false;

            // receive request -------------------------------------------
            reader.Attach(connection);

            // request line
            string httpMethod;
            string requestUri;
            string httpVersion;

            reader.ReadStringToBlank(out httpMethod);
            reader.ReadStringToBlank(out requestUri);
            reader.ReadFieldValue(out httpVersion);
            if (reader.Status != HttpStatus.BeforeContent)  // error
            {
                reader.Detach();
                connectionClose = true;
                return;
            }

            context.RequestMethod = httpMethod;
            context.RequestUri    = requestUri;
            // ignore version

            // headers
            string fieldName;
            string fieldValue;
            int    requestContentLength = -1;

            reader.ReadFieldName(out fieldName);
            while (reader.Status == HttpStatus.BeforeContent)
            {
                reader.ReadFieldValue(out fieldValue);
                if (fieldValue != null)
                {
                    Contract.Assert(reader.Status ==
                                    HttpStatus.BeforeContent);
                    if (fieldName == "Connection")
                    {
                        context.ConnectionClose =
                            ((fieldValue == "close") ||
                             (fieldValue == "Close"));
                    }
                    else if (fieldName == "Content-Type")
                    {
                        context.RequestContentType = fieldValue;
                    }
                    else if (fieldName == "Content-Length")
                    {
                        if (Utilities.TryParseUInt32(fieldValue,
                                                     out requestContentLength))
                        {
                            // content length is now known
                        }
                        else
                        {
                            reader.Status = HttpStatus.SyntaxError;
                            reader.Detach();
                            connectionClose = true;
                            return;
                        }
                    }
                }
                else
                {
                    // it's ok to skip header whose value is too long
                }
                Contract.Assert(reader.Status == HttpStatus.BeforeContent);
                reader.ReadFieldName(out fieldName);
            }
            if (reader.Status != HttpStatus.InContent)
            {
                reader.Detach();
                connectionClose = true;
                return;
            }

            // content
            if (requestContentLength > 0)
            {
                // receive content
                var requestContent = new byte[requestContentLength];
                int toRead         = requestContentLength;
                var read           = 0;
                while ((toRead > 0) && (read >= 0))
                {
                    // already read: requestContentLength - toRead
                    read = reader.ReadContent(requestContent,
                                              requestContentLength - toRead, toRead);
                    if (read < 0)
                    {
                        break;
                    }                           // timeout or shutdown
                    toRead = toRead - read;
                }
                try
                {
                    char[] chars = Encoding.UTF8.GetChars(requestContent);
                    context.RequestContent = new string(chars);
                }
                catch (Exception)
                {
                    context.RequestContentType = "text/plain";
                    context.RequestContent     = "request content is not in UTF8 format";
                    Debug.Print(context.RequestContent);
                    // TODO signal wrong content format through HTTP status code 400 (Bad Request)?
                }
            }

            reader.Detach();
            if (reader.Status != HttpStatus.InContent)
            {
                connectionClose = true;
                return;
            }

            // delegate request processing to a request handler ----------
            var match = false;

            foreach (Element e in requestRouting)
            {
                if (context.RequestMatch(e))
                {
                    bool connClose = context.ConnectionClose;
                    context.ResponseStatusCode = -1;                                    // undefined
                    Contract.Requires(context.ResponseContentType != null);
                    Contract.Requires(context.ResponseContentType == "text/plain");     // default
                    try
                    {
                        e.Handler(context);
                    }
                    catch (Exception h)
                    {
                        Debug.Print("exception in request handler: " + h); // TODO how to better handle handler exceptions?
                        throw;                                             // rethrow, to avoid masking of errors
                    }
                    Contract.Ensures(context.ResponseStatusCode >= 100);
                    Contract.Ensures(context.ResponseStatusCode < 600);
                    Contract.Ensures(context.ResponseContentType != null);
                    Contract.Ensures(context.ResponseContentType.Length > 0);
                    // make sure that handler has not reset connectionClose flag:
                    Contract.Ensures((!connClose) || (context.ConnectionClose));
                    match = true;
                    break;
                }
            }
            if (!match)
            {
                context.ResponseStatusCode  = 404;   // Not Found
                context.ResponseContentType = "text/plain";
                context.ResponseContent     = null;
            }

            uint availableMemory = Debug.GC(true);

            Debug.Print(context.RequestMethod + " " +
                        context.RequestUri + " -> " +
                        context.ResponseStatusCode + " [" + availableMemory + "]");

            // send response ---------------------------------------------
            writer.Attach(connection);

            // status line
            writer.WriteString("HTTP/1.1 ");
            writer.WriteString(context.ResponseStatusCode.ToString());
            writer.WriteLine(" ");  // omit optional reason phrase

            // headers
            if (connectionClose)   // TODO (context.ConnectionClose)
            {
                writer.WriteLine("Connection: close");
            }
            byte[] responseBuffer = null;
            var    responseLength = 0;

            if (context.ResponseContent != null)
            {
                responseBuffer =
                    Encoding.UTF8.GetBytes(context.ResponseContent);
                responseLength = responseBuffer.Length;
                writer.WriteString("Content-Type: ");
                writer.WriteLine(context.ResponseContentType);
            }
            else
            {
                responseLength = 0;
            }
            writer.WriteString("Content-Length: ");
            writer.WriteLine(responseLength.ToString());
            if (context.ResponseMaxAge > 0)
            {
                writer.WriteLine("Cache-Control: max-age=" + context.ResponseMaxAge);
            }
            else if (context.ResponseMaxAge == 0)
            {
                writer.WriteLine("Cache-Control: no-cache");
            }

            // content
            writer.WriteBeginOfContent();
            if (context.ResponseContent != null)    // send content
            {
                writer.WriteContent(responseBuffer, 0, responseLength);
            }

            writer.Detach();
            connectionClose = context.ConnectionClose;
        }
Пример #19
0
        static void HandleHello( RequestHandlerContext context)
        {
            string s = "<h1> hello webber " + DateTime.Now.ToString();

            context.SetResponse(s, "text/html");
        }
Пример #20
0
 static void HandlePostOff(RequestHandlerContext context)
 {
     context.ResponseStatusCode = 200;
     lightWrite(false);
 }
Пример #21
0
        /// <summary>
        /// Private method that handles an incoming request.
        /// It sets up a RequestHandlerContext instance with the data from
        /// the incoming HTTP request, finds a suitable request handler to
        /// produce the response, and then sends the response as an HTTP
        /// response back to the client.
        /// Preconditions
        ///     "connection is open"
        ///     serviceRoot != null
        ///     serviceRoot.Length > 8
        ///     "serviceRoot starts with 'http://' and ends with '/'"
        ///     requestRouting != null
        /// </summary>
        /// <param name="connection">Open TCP/IP connection</param>
        /// <param name="serviceRoot">The absolute URI that is a prefix of
        /// all request URIs that this web service supports. It must start
        /// with "http://" and must end with "/".</param>
        /// <param name="relayDomain">Host name or Internet address of the
        /// relay to be used, or null if no relay is used</param>
        /// <param name="requestRouting">Collection of
        ///   { request pattern, request handler}
        /// pairs</param>
        /// <param name="connectionClose">Return parameter that indicates
        /// that the connection should be closed after this call. This may
        /// be because the incoming request has a "Connection: close"
        /// header, because the request handler has set the
        /// ConnectionClose property, or because some error occurred.
        /// </param>
        internal static void ConsumeRequest(Stream connection,
            string serviceRoot, string relayDomain,
            RequestRouting requestRouting,
            ref bool connectionClose)
        {
            Contract.Requires(connection != null);
            Contract.Requires(serviceRoot != null);
            Contract.Requires(serviceRoot.Length > 8);
            Contract.Requires(serviceRoot.Substring(0, 7) == "http://");
            Contract.Requires(serviceRoot[serviceRoot.Length - 1] != '/');
            Contract.Requires(requestRouting != null);

            // initialization --------------------------------------------
            HttpReader reader = new HttpReader();
            HttpWriter writer = new HttpWriter();
            var context = new RequestHandlerContext(serviceRoot,
                relayDomain);
            // Both client and server may request closing the connection.
            // Initially, we assume that neither one wants to close the
            // connection.
            context.ConnectionClose = false;

            // receive request -------------------------------------------
            reader.Attach(connection);

            // request line
            string httpMethod;
            string requestUri;
            string httpVersion;

            reader.ReadStringToBlank(out httpMethod);
            reader.ReadStringToBlank(out requestUri);
            reader.ReadFieldValue(out httpVersion);
            if (reader.Status != HttpStatus.BeforeContent)  // error
            {
                reader.Detach();
                connectionClose = true;
                return;
            }

            context.RequestMethod = httpMethod;
            context.RequestUri = requestUri;
            // ignore version

            // headers
            string fieldName;
            string fieldValue;
            int requestContentLength = -1;
            reader.ReadFieldName(out fieldName);
            while (reader.Status == HttpStatus.BeforeContent)
            {
                reader.ReadFieldValue(out fieldValue);
                if (fieldValue != null)
                {
                    Contract.Assert(reader.Status ==
                                    HttpStatus.BeforeContent);
                    if (fieldName == "Connection")
                    {
                        context.ConnectionClose =
                            ((fieldValue == "close") ||
                             (fieldValue == "Close"));
                    }
                    else if (fieldName == "Content-Type")
                    {
                        context.RequestContentType = fieldValue;
                    }
                    else if (fieldName == "Content-Length")
                    {
                        if (Utilities.TryParseUInt32(fieldValue,
                            out requestContentLength))
                        {
                            // content length is now known
                        }
                        else
                        {
                            reader.Status = HttpStatus.SyntaxError;
                            reader.Detach();
                            connectionClose = true;
                            return;
                        }
                    }
                }
                else
                {
                    // it's ok to skip header whose value is too long
                }
                Contract.Assert(reader.Status == HttpStatus.BeforeContent);
                reader.ReadFieldName(out fieldName);
            }
            if (reader.Status != HttpStatus.InContent)
            {
                reader.Detach();
                connectionClose = true;
                return;
            }

            // content
            if (requestContentLength > 0)
            {
                // receive content
                var requestContent = new byte[requestContentLength];
                int toRead = requestContentLength;
                var read = 0;
                while ((toRead > 0) && (read >= 0))
                {
                    // already read: requestContentLength - toRead
                    read = reader.ReadContent(requestContent,
                        requestContentLength - toRead, toRead);
                    if (read < 0) { break; }    // timeout or shutdown
                    toRead = toRead - read;
                }
                try
                {
                    char[] chars = Encoding.UTF8.GetChars(requestContent);
                    context.RequestContent = new string(chars);
                }
                catch (Exception)
                {
                    context.RequestContentType = "text/plain";
                    context.RequestContent = "request content is not in UTF8 format";
                    Debug.Print(context.RequestContent);
                    // TODO signal wrong content format through HTTP status code 400 (Bad Request)?
                }
            }

            reader.Detach();
            if (reader.Status != HttpStatus.InContent)
            {
                connectionClose = true;
                return;
            }

            // delegate request processing to a request handler ----------
            var match = false;
            foreach (Element e in requestRouting)
            {
                if (context.RequestMatch(e))
                {
                    bool connClose = context.ConnectionClose;
                    context.ResponseStatusCode = -1;                                    // undefined
                    Contract.Requires(context.ResponseContentType != null);
                    Contract.Requires(context.ResponseContentType == "text/plain");     // default
                    try
                    {
                        e.Handler(context);
                    }
                    catch (Exception h)
                    {
                        Debug.Print("exception in request handler: " + h);    // TODO how to better handle handler exceptions?
                        throw;                                  // rethrow, to avoid masking of errors
                    }
                    Contract.Ensures(context.ResponseStatusCode >= 100);
                    Contract.Ensures(context.ResponseStatusCode < 600);
                    Contract.Ensures(context.ResponseContentType != null);
                    Contract.Ensures(context.ResponseContentType.Length > 0);
                    // make sure that handler has not reset connectionClose flag:
                    Contract.Ensures((!connClose) || (context.ConnectionClose));
                    match = true;
                    break;
                }
            }
            if (!match)
            {
                context.ResponseStatusCode = 404;    // Not Found
                context.ResponseContentType = "text/plain";
                context.ResponseContent = null;
            }

            uint availableMemory = Debug.GC(true);
            Debug.Print(context.RequestMethod + " " +
                        context.RequestUri + " -> " +
                        context.ResponseStatusCode + " [" + availableMemory + "]");

            // send response ---------------------------------------------
            writer.Attach(connection);

            // status line
            writer.WriteString("HTTP/1.1 ");
            writer.WriteString(context.ResponseStatusCode.ToString());
            writer.WriteLine(" ");  // omit optional reason phrase

            // headers
            if (connectionClose)   // TODO (context.ConnectionClose)
            {
                writer.WriteLine("Connection: close");
            }
            byte[] responseBuffer = null;
            var responseLength = 0;
            if (context.ResponseContent != null)
            {
                responseBuffer =
                    Encoding.UTF8.GetBytes(context.ResponseContent);
                responseLength = responseBuffer.Length;
                writer.WriteString("Content-Type: ");
                writer.WriteLine(context.ResponseContentType);
            }
            else
            {
                responseLength = 0;
            }
            writer.WriteString("Content-Length: ");
            writer.WriteLine(responseLength.ToString());
            if (context.ResponseMaxAge > 0)
            {
                writer.WriteLine("Cache-Control: max-age=" + context.ResponseMaxAge);
            }
            else if (context.ResponseMaxAge == 0)
            {
                writer.WriteLine("Cache-Control: no-cache");
            }

            // content
            writer.WriteBeginOfContent();
            if (context.ResponseContent != null)    // send content
            {
                writer.WriteContent(responseBuffer, 0, responseLength);
            }

            writer.Detach();
            connectionClose = context.ConnectionClose;
        }
Пример #22
0
 /// <summary>
 /// Interprets an HTTP request and produces an appropriate HTTP
 /// response.
 /// If the manipulated variable is not open, Open is called first.
 /// Preconditions
 ///     context != null
 /// </summary>
 /// <param name="context">Provides access to the received request,
 /// the server, and to the (empty) response.</param>
 public void HandleRequest(RequestHandlerContext context)
 {
     Contract.Requires(context != null);
     if (!initialized) { Open(); }
     if (context.RequestMethod == "PUT")
     {
         object setpoint;
         if (FromHttpRequest(context, out setpoint))
         {
             // setpoint may be null
             ToActuator(setpoint);
             lastSetpoint = setpoint;
             context.ResponseStatusCode = 200;    // OK
         }
         else
         {
             context.ResponseStatusCode = 400;    // Bad Request
         }
     }
     else if (context.RequestMethod == "GET")
     {
         // lastSetpoint may be null
         ToHttpResponse(context, lastSetpoint);
         context.ResponseStatusCode = 200;    // OK
     }
     else
     {
         context.ResponseStatusCode = 405;    // Method Not Allowed
     }
 }
Пример #23
0
        /// <summary>
        /// Interprets an HTTP request and produces an appropriate HTTP
        /// response.
        /// If the measured variable is not open, Open is called first.
        /// Preconditions
        ///     context != null
        /// </summary>
        /// <param name="context">Provides access to the received request,
        /// the server, and to the (empty) response.</param>
        public void HandleRequest(RequestHandlerContext context)
        {
            Contract.Requires(context != null);
            if (!initialized) { Open(); }

            context.ResponseMaxAge = 0;         // no caching (default is -1, i.e., no cache header)
            object sample = FromSensor();
            // sample may be null
            ToHttpResponse(context, sample);
        }
Пример #24
0
 /// <summary>
 /// Converts an HTTP request message body to a double object.
 /// content is not null if conversion was successful.
 /// The return value indicates whether conversion was successful.
 /// Preconditions
 ///     context != null
 /// Postconditions
 ///     Result =>
 ///         content != null
 ///         content is double
 ///         "content contains deserialized representation of
 ///          context.RequestContent"
 ///     !Result =>
 ///         content == null
 ///         "context.RequestContent could not be converted to a
 ///          C# object"
 /// </summary>
 public static bool TryDeserializeDouble(RequestHandlerContext context,
     out object content)
 {
     string s = context.RequestContent;
     double x = 0;
     int decimalDiv = 0;
     content = null;
     foreach (char c in s)
     {
         if ((c == '.') && (decimalDiv == 0)) { decimalDiv = 1; }
         else if ((c < '0') || (c > '9')) { return false; }
         else
         {
             x = x * 10;
             decimalDiv = decimalDiv * 10;
             x = x + (int)(c - '0');
         }
     }
     if (decimalDiv != 0) { x = x / decimalDiv; }
     content = x;
     return true;
 }
        /// <summary>
        /// Converts an HTTP request message body to a double object.
        /// content is not null if conversion was successful.
        /// The return value indicates whether conversion was successful.
        /// Preconditions
        ///     context != null
        /// Postconditions
        ///     Result =>
        ///         content != null
        ///         content is double
        ///         "content contains deserialized representation of
        ///          context.RequestContent"
        ///     !Result =>
        ///         content == null
        ///         "context.RequestContent could not be converted to a
        ///          C# object"
        /// </summary>
        public static bool TryDeserializeDouble(RequestHandlerContext context,
            out object content)
        {
            // TODO remove
            if (context == null) Microsoft.SPOT.Debug.Print("context is null");
            if (context.RequestContent == null) Microsoft.SPOT.Debug.Print("RequestContent is null");

            string s = context.RequestContent;
            double x = 0;
            int decimalDiv = 0;
            content = null;
            foreach (char c in s)
            {
                if ((c == '.') && (decimalDiv == 0)) { decimalDiv = 1; }
                else if ((c < '0') || (c > '9')) { return false; }
                else
                {
                    x = x * 10;
                    decimalDiv = decimalDiv * 10;
                    x = x + (int)(c - '0');
                }
            }
            if (decimalDiv != 0) { x = x / decimalDiv; }
            content = x;
            return true;
        }
 /// <summary>
 /// Converts an object to an HTTP response message body.
 /// content may be null.
 /// If the content is null, the string "null" is produced as
 /// its representation. Otherwise, the object's ToString
 /// method is called for producing the representation.
 /// Preconditions
 ///     context != null
 /// Postconditions
 ///     "context.RequestContent contains serialized representation of
 ///      content object"
 ///     context.ResponseContentType == "text/plain"
 /// </summary>
 public static void Serialize(RequestHandlerContext context,
     object content)
 {
     string s = (content != null) ? content.ToString() : "null";
     context.SetResponse(s, "text/plain");
 }
Пример #27
0
 static void HandlePostOn(RequestHandlerContext context)
 {
     context.ResponseStatusCode = 200;
     remoteLight.Write(true);
 }
 /// <summary>
 /// Converts an HTTP request message body to an int object.
 /// content is not null if conversion was successful.
 /// The return value indicates whether conversion was successful.
 /// Preconditions
 ///     context != null
 /// Postconditions
 ///     Result =>
 ///         content != null
 ///         content is int
 ///         "content contains deserialized representation of
 ///          context.RequestContent"
 ///     !Result =>
 ///         content == null
 ///         "context.RequestContent could not be converted to a
 ///          C# object"
 /// </summary>
 public static bool TryDeserializeInt(RequestHandlerContext context,
     out object content)
 {
     string s = context.RequestContent;
     int x;
     if (Utilities.TryParseUInt32(s, out x))
     {
         content = x;
         return true;
     }
     else
     {
         content = null;
         return false;
     }
 }
Пример #29
0
 static void HandleOn(RequestHandlerContext context)
 {
     onboardLedBlink = true;
     string s = "<h1>HANDLING LED<h2>Led Blink is ON now";
     context.SetResponse(s, "text/html");
 }
Пример #30
0
        /// <summary>
        /// Private method that handles an incoming request.
        /// It sets up a RequestHandlerContext instance with the data from
        /// the incoming HTTP request, finds a suitable request handler to
        /// produce the response, and then sends the response as an HTTP
        /// response back to the client.
        /// Preconditions
        ///     "connection is open"
        ///     serviceRoot != null
        ///     serviceRoot.Length > 8
        ///     "serviceRoot starts with 'http://' and ends with '/'"
        ///     requestRouting != null
        /// </summary>
        /// <param name="connection">Open TCP/IP connection</param>
        /// <param name="serviceRoot">The absolute URI that is a prefix of
        /// all request URIs that this web service supports. It must start
        /// with "http://" and must end with "/".</param>
        /// <param name="relayDomain">Host name or Internet address of the
        /// relay to be used, or null if no relay is used</param>
        /// <param name="requestRouting">Collection of
        ///   { request pattern, request handler}
        /// pairs</param>
        /// <param name="connectionClose">Return parameter that indicates
        /// that the connection should be closed after this call. This may
        /// be because the incoming request has a "Connection: close"
        /// header, because the request handler has set the
        /// ConnectionClose property, or because some error occurred.
        /// </param>
        internal static void ConsumeRequest(Stream connection,
            string serviceRoot, string relayDomain,
            RequestRouting requestRouting,
            bool catchRequestFailures,
            ref bool connectionClose)
        {
            Contract.Requires(connection != null);
            Contract.Requires(serviceRoot != null);
            Contract.Requires(serviceRoot.Length > 8);
            Contract.Requires(serviceRoot.Substring(0, 7) == "http://");
            Contract.Requires(serviceRoot[serviceRoot.Length - 1] != '/');
            Contract.Requires(requestRouting != null);

            // initialization --------------------------------------------
            DebugPrint("HttpServer: ConsumeRequest - initialize");
            HttpReader reader = new HttpReader();
            HttpWriter writer = new HttpWriter();
            var context = new RequestHandlerContext(serviceRoot,
                relayDomain);

            // receive request -------------------------------------------
            reader.Attach(connection);

            // read request line
            DebugPrint("HttpServer: ConsumeRequest - read request line");
            string httpMethod;
            string requestUri;
            string httpVersion;

            reader.ReadStringToBlank(out httpMethod);
            reader.ReadStringToBlank(out requestUri);
            if (reader.Status == HttpStatus.RequestUriTooLong)
            {
                context.ResponseStatusCode = 414;    // Request-URI Too Long
                context.ResponseContentType = "text/plain";
                context.ResponseContent = "request URI too long";
                reader.Detach();
                connectionClose = true;
                DebugPrint("HttpServer: ConsumeRequest - request URI too long!");
                return;
            }
            reader.ReadFieldValue(out httpVersion);
            if (reader.Status != HttpStatus.BeforeContent)  // error
            {
                reader.Detach();
                connectionClose = true;
                DebugPrint("HttpServer: ConsumeRequest - could not read HTTP version!");
                return;
            }

            context.RequestMethod = httpMethod;
            context.RequestUri = requestUri;
            // ignore version

            // headers
            DebugPrint("HttpServer: ConsumeRequest - read headers");
            string fieldName;
            string fieldValue;
            int requestContentLength = -1;
            reader.ReadFieldName(out fieldName);
            while (reader.Status == HttpStatus.BeforeContent)
            {
                reader.ReadFieldValue(out fieldValue);
                if (fieldValue != null)
                {
                    Contract.Assert(reader.Status ==
                                    HttpStatus.BeforeContent);
                    if (fieldName == "Connection")
                    {
                        connectionClose =
                            (connectionClose ||
                            (fieldValue == "close") ||
                             (fieldValue == "Close"));
                    }
                    else if (fieldName == "Content-Type")
                    {
                        context.RequestContentType = fieldValue;
                        DebugPrint("HttpServer: ConsumeRequest - request Content-Type: " + fieldValue);
                    }
                    else if (fieldName == "Content-Length")
                    {
                        if (Utilities.TryParseUInt32(fieldValue,
                            out requestContentLength))
                        {
                            // content length is now known
                            DebugPrint("HttpServer: ConsumeRequest - request Content-Length: " + requestContentLength);
                        }
                        else
                        {
                            DebugPrint("HttpServer: ConsumeRequest - request syntax error");
                            //reader.Status = HttpStatus.SyntaxError;
                            reader.Detach();
                            connectionClose = true;
                            return;
                        }
                    }
                }
                else
                {
                    // it's ok to skip header whose value is too long
                }
                Contract.Assert(reader.Status == HttpStatus.BeforeContent);
                reader.ReadFieldName(out fieldName);
            }
            if (reader.Status != HttpStatus.InContent)
            {
                reader.Detach();
                connectionClose = true;
                return;
            }

            // content
            DebugPrint("HttpServer: ConsumeRequest - read content");
            context.RequestContentBytes = null;
            if (requestContentLength > 0)
            {
                // receive content
                context.RequestContentBytes = new byte[requestContentLength];
                int toRead = requestContentLength;
                var read = 0;
                while ((toRead > 0) && (read >= 0))
                {
                    // already read: requestContentLength - toRead
                    read = reader.ReadContent(context.RequestContentBytes,
                        requestContentLength - toRead, toRead);
                    if (read < 0) { break; }    // timeout or shutdown
                    toRead = toRead - read;
                }
            }

            reader.Detach();
            if (reader.Status != HttpStatus.InContent)
            {
                connectionClose = true;
                return;
            }

            // delegate request processing to a request handler ----------
            DebugPrint("HttpServer: ConsumeRequest - call request handler");
            var match = false;
            foreach (RoutingElement e in requestRouting)
            {
                if (context.RequestMatch(e))
                {
                    context.ConnectionClose = false;
                    context.ResponseStatusCode = -1;                                    // undefined
                    Contract.Requires(context.ResponseContentType != null);
                    Contract.Requires(context.ResponseContentType == "text/plain");     // default

                    e.Handler(context);
                    if (catchRequestFailures)
                    {
                        try
                        {
                            e.Handler(context);
                        }
                        catch (Exception h)
                        {
                            DebugPrint("HttpServer: exception in request handler: " + h);
                        }
                    }
                    else
                    {
                        e.Handler(context);
                    }

                    Contract.Ensures(context.ResponseStatusCode >= 100);
                    Contract.Ensures(context.ResponseStatusCode < 600);
                    Contract.Ensures(context.ResponseContentType != null);
                    Contract.Ensures(context.ResponseContentType.Length > 0);
                    connectionClose = connectionClose || context.ConnectionClose;
                    match = true;
                    break;
                }
            }
            if (!match)
            {
                context.ResponseStatusCode = 404;    // Not Found
                context.ResponseContentType = "text/plain";
                context.ResponseContent = "404 error - resource not found";
                DebugPrint("HttpServer: no matching request handler found");
            }
            Contract.Assert(context.ResponseContentType != null);

            // send response ---------------------------------------------
            DebugPrint("HttpServer: ConsumeRequest - send response");
            writer.Attach(connection);

            // status line
            DebugPrint("HttpServer: ConsumeRequest - send status line");
            writer.WriteString("HTTP/1.1 ");
            writer.WriteString(context.ResponseStatusCode.ToString());
            writer.WriteLine(" ");  // omit optional reason phrase

            // headers
            DebugPrint("HttpServer: ConsumeRequest - send headers");
            if (connectionClose)
            {
                writer.WriteLine("Connection: close");
            }
            if (context.ResponseMaxAge > 0)
            {
                writer.WriteLine("Cache-Control: max-age=" + context.ResponseMaxAge);
            }
            else if (context.ResponseMaxAge == 0)
            {
                writer.WriteLine("Cache-Control: no-cache");
            }
            writer.WriteString("Content-Type: ");
            writer.WriteLine(context.ResponseContentType);
            DebugPrint("HttpServer: ConsumeRequest - response Content-Type: " + context.ResponseContentType);

            if (context.ResponseContent != null)
            {
                DebugPrint("HttpServer: ConsumeRequest - response content is text");
                context.ResponseContentBytes =
                    Encoding.UTF8.GetBytes(context.ResponseContent);
                Contract.Assert(context.ResponseContentBytes != null);
            }
            if (context.ResponseContentBytes != null)
            {
                DebugPrint("HttpServer: ConsumeRequest - content available as binary");
                if (context.ResponseContentLength == -1)
                {
                    context.ResponseContentLength = context.ResponseContentBytes.Length;    // default is to take the entire buffer
                }
                writer.WriteString("Content-Length: ");
                writer.WriteLine(context.ResponseContentLength.ToString());
                DebugPrint("HttpServer: ConsumeRequest - response Content-Length: " + context.ResponseContentLength);
            }
            else
            {
                writer.WriteString("Content-Length: 0");
                DebugPrint("HttpServer: ConsumeRequest - response Content-Length: 0");
            }

            // content
            DebugPrint("HttpServer: ConsumeRequest - send content");
            writer.WriteBeginOfContent();
            if (context.ResponseContentBytes != null)    // send content
            {
                writer.WriteContent(context.ResponseContentBytes, 0, context.ResponseContentLength);
            }
            DebugPrint("HttpServer: response sent");

            writer.Detach();

            uint availableMemory = Microsoft.SPOT.Debug.GC(true);   // TODO define portable abstraction for free memory
            Trace.TraceInformation(context.RequestMethod + " " +
                                   context.RequestUri + " -> " +
                                   context.ResponseStatusCode + " [" + availableMemory + "]");
        }