Posts
80
Comments
214
Trackbacks
0
HTTP request class for the .NET Microframework
As I wrote in my first blog entry, I've been selected for round 2 of the "dare to dream different" challenge.
My idea involves a lot of internet connectivity and I needed a way to make HTTP requests from my .NET framework device (I'm stil waiting for the real device, but the emulator is great to test network connectivity).
I found a very good sample on Elze Kool's blog and I used it as a starting point for my own HTTP request class.
It's a simple class that allows you to send a request to any HTTP server.
It parses the reply and implements a stream interface, allowing you to read data from it using a TextReader, an XML reader or reading its contents in any way you like.
It's main method (Send) accept a URL as input. The URL must be formatted as:
<protocol>://<servername>:<port>/<path>

<protocol> is usually "http" but you may use other http-based protocols.
<port> is optional and, if not specified, the object will use HTTP default port (80).
Don't forget to call Close when you are done using the object to avoid "zombie" TCP/IP connections that can waste resources on your device and on the server.
It's not a coding masterpiece and I tested it only with a couple of different serves, so if you want to suggest improvements, feel free to do that in the comments section.

using System;
using System.IO;
using System.Net;
using System.Net.Sockets;
using System.Text;
using Microsoft.SPOT;

namespace Calendar
{
    class HTTPException : Exception
    {
        int code;

        public HTTPException(int code) : base("HTTP error "+code.ToString())
        {
            this.code = code;
        }

        public HTTPException() : base("Invalid HTTP reply")
        {
            code = -1;
        }
    }

    class HTTPRequest : Stream
    {
        // socket used for HTTP connection
        protected Socket httpsocket;
                        
        // content length
        protected long size;
        
        // current position
        protected long position;

        public HTTPRequest()
        {
            size = 0;
            position = 0;
        }

        /**
         * We need a custom readline function. Using a standard textreader could prevent usage of other kind of readers (XML etc.) on the stream.
         */
        protected string ReadLine()
        {
            string line = "";

            byte[] data = new byte[1];

            while (Read(data, 0, 1) != 0)
            {
                // checks for carriage return
                if (data[0] == 0x0d)
                {
                    // discards line feed
                    Read(data, 0, 1);

                    // returns the string
                    return line;
                }

                char[] chars=UTF8Encoding.UTF8.GetChars(data);

                line += chars[0];
            }
            return line;
        }

        /**
         * Sends an HTTP reply and initializes the stream that may be used to read the reply
         */
        public void Send(string url)
        {
            // parses the url, splitting server and path
            int serverindex = url.IndexOf("//");

            if (serverindex == -1)
                throw new ArgumentException("Invalid URL, can't find server name.");

            string server;
            string path;

            int port = 80;

            int pathindex = url.IndexOf("/",serverindex+2);

            if (pathindex == -1)
                throw new ArgumentException("Invalid URL, can't find resource path.");

            int portindex = url.IndexOf(":",serverindex+2);

            // port is not mandatory, if no port is specified, port 80 is used
            if (portindex != -1)
            {
                string portstring = url.Substring(portindex + 1, pathindex - portindex - 1);

                server = url.Substring(serverindex + 2, portindex - serverindex - 2);
                path = url.Substring(pathindex + 1);
                port = Int32.Parse(portstring);
            }
            else
            {            
                server = url.Substring(serverindex+2,pathindex-serverindex-2);
                path = url.Substring(pathindex);            
            }

            // tries to solve server name
            IPHostEntry host = Dns.GetHostEntry(server);

            // connects to the server
            httpsocket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);

            // builds up the HTTP request
            string requestheader =  "GET "+path+" HTTP/1.1\r\nHost:"+server+"\r\nConnection: Close\r\nAccept-Charset: utf-8;\r\nPragma:    no-cache\r\nCache-Control: no-cache\r\n\r\n";

            httpsocket.Connect(new IPEndPoint(host.AddressList[0], port));

            Byte[] requestarray = Encoding.UTF8.GetBytes(requestheader);

            httpsocket.Send(requestarray);

            // parses the HTTP reply
            string line = ReadLine();

            // the first line contains the return code
            if (line.IndexOf("HTTP") != 0)
                throw new HTTPException();

            string codestring = line.Substring(line.IndexOf(" ")+1, 3);

            int httpcode = Int32.Parse(codestring);

            if (httpcode != 200)
                throw new HTTPException(httpcode);

            while (line.Length != 0)
            {
                line = ReadLine();

                //searches content lenght header
                if (line.IndexOf("Content-Length:") == 0)
                {
                    string lengthstring = line.Substring(15).Trim();

                    size = Int32.Parse(lengthstring);
                }
            }

            // position starts to count from here
            position = 0;

            // does not close the stream (there's no way to detach it from the socket)
        }

        public override void Close()
        {
            if (httpsocket != null)
                httpsocket.Close();
        }

        public override bool CanRead
        {
            get { return true; }
        }

        public override bool CanSeek
        {
            get { return false; }
        }

        public override bool CanWrite
        {
            get { return false; }
        }

        public override long Length
        {
            get { return size; }
        }

        public override long Position
        {
            get { return position; }
            set { throw new NotImplementedException(); }
        }

        public override void Flush()
        {
            throw new NotImplementedException();
        }

        public override void SetLength(long value)
        {
            throw new NotImplementedException();
        }

        public override int Read(byte[] buffer, int offset, int count)
        {
            int readt=httpsocket.Receive(buffer,offset,count,SocketFlags.None);

            position += readt;
            return readt;
        }

        public override void Write(byte[] buffer, int offset, int count)
        {
            throw new NotImplementedException();
        }

        public override long Seek(long offset, SeekOrigin origin)
        {
            throw new NotImplementedException();
        }
    }
}
posted on Friday, January 16, 2009 2:00 PM Print
Comments
No comments posted yet.

Post Comment

Title *
Name *
Email
Comment *  
Verification
Toradex logo

Cookies in Use
Tag Cloud