HTTP Server Response Headers

Collapse
X
 
  • Time
  • Show
Clear All
new posts
  • Ollie Shotton
    New Member
    • Jan 2011
    • 12

    HTTP Server Response Headers

    Hi i need to make a BASIC HTTP server for a project using JUST TCP/IP Sockets so please don't suggest anything that would use some of C#'s higher level networking components, Thanks =).

    Anyway my problem:

    i have created the server and it all works so far but i haven't implemented the HTTP Headers properly, if i leave out all the headers i wrote then some browsers work fine with it (can't remember which) but when i add in the headers (and change them around trying to get it to work) it only shows part of the page or doesn't load the css file and once it just showed half of the html code!

    btw i dont know if this makes a difference but i use the link tag in my main.html head to get the css file.
    <link rel="stylesheet " type="text/css" href="mainStyle sheet.css"/>

    and before anyone asks, the html file works fine if i just run it straight on the browser! =P

    Here is some of my code:
    Code:
    class ConnectionThread
        {
            public ConnectionThread(Socket socket)
            {
                connection = socket;
            }
     
            Socket connection = null;
            NetworkStream mainStream = null;
            BinaryReader inStream = null;
            BinaryWriter outStream = null;
     
            public void run()
            {
                mainStream = new NetworkStream(connection);
     
                inStream = new BinaryReader(mainStream);
                outStream = new BinaryWriter(mainStream);
     
                byte b = 0;
                string s = "";
                string[] requestData = null;
                string requestedPage = null;
     
                try
                {
                    while (mainStream.DataAvailable)
                    {
                        b = inStream.ReadByte();
                        s += (char)b;
                    }
     
                    requestData = s.Split('\r');
     
                    int l = requestData.Length;
     
                    //check to see if it got the request data (sometimes it doesn't)
                    if (l > 1) 
                    {
                        //get the page the browser requests
                        requestedPage = requestData[0].Split(' ')[1];
     
                        //calls the method which sends the browser the page to be displayed
                        theSwitch(requestedPage);
                    }
                    else
                    {
                        //call method again to try and get the request data
                        run();
                    }
                }            
                catch (Exception exp)
                {
                    Console.WriteLine("Unexpected error.");
                    Console.WriteLine("Error caused by: " + exp.Message);                
                }
            }
     
            void theSwitch(string item)
            {
                string file = null;
                char[] output = null;
                string head = null;
     
                try
                {
                    switch (item)
                    {
                        case "/":
     
                            file = readFile("Resources/main.html");
     
                            head += "HTTP/1.1 100 Continue\r\n";
                            head += String.Format("{0:ddd, dd MMM yy HH:mm:ss} GMT\r\n", DateTime.Now);
                            head += "Server: Ollie's Server v1.0\r\n";
                            head += "Cache-Control: none\r\n";
                            head += "Content-Type: text/html\r\n";
                            head += string.Format("Content-Length: {0}\r\n", file.Length);
                            head += "<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 4.0 Transitional//EN\">\r\n";
     
                            Console.WriteLine(head);
                            output = (head + file).ToArray();
     
                            outStream.Write(output);
     
                            break;
     
                        case "Resources/mainStylesheet.css":
     
                            file = readFile("/mainStylesheet.css");
     
                            head += "HTTP/ 1.1 100 Continue\r\n";
                            head += String.Format("{0:ddd, dd MMM yy HH:mm:ss} GMT\r\n", DateTime.Now);
                            head += "Server: Ollie's Server v1.0\r\n";
                            head += "Cache-Control: none\r\n";
                            head += "Content-Type: text/css\r\n";
                            head += string.Format("Content-Length: {0}\r\n", file.Length);
     
                            output = (head + file).ToArray();
     
                            outStream.Write(file);
     
                            break;
     
                        case "Resources/favicon.ico":
     
                            MemoryStream ms = new MemoryStream();
                            System.Drawing.Image i = System.Drawing.Image.FromFile("Resources/favicon.gif");
                            i.Save(ms, System.Drawing.Imaging.ImageFormat.Gif);
     
                            head += "HTTP/1.1 206 Partial content";
                            head += String.Format("{0:ddd, dd MMM yy HH:mm:ss} GMT\r\n", DateTime.Now);
                            head += "Server: Ollie's Server v1.0\r\n";
                            head += "Cache-Control: none\r\n";
                            head += "Content-Type: image/gif\r\n";
                            head += string.Format("Content-Length: {0}\r\n", ms.Length);
     
                            output = (head + ms).ToArray();
     
                            outStream.Write(output);
     
                            break;
     
                        default:
     
                            Console.WriteLine("Not Found");
                            Console.WriteLine();
     
                            break;
                    }
     
                    inStream.Close();
     
                    outStream.Flush();
                    outStream.Close();
     
                    mainStream.Close();
     
                    connection.Close();
     
                }
                catch (Exception exp)
                {
                    Console.WriteLine("Unexpected error.");
                    Console.WriteLine("Error caused by: " + exp.Message);
                }
            }
     
            //method that returns a string of the html or css file to be sent to the browser
            private string readFile(string file)
            {
                string output = null;
     
                try
                {
                    StreamReader reader = new StreamReader(file);
                    while (!reader.EndOfStream)
                    {
                        output += reader.ReadToEnd();
                    }
                }
                catch (Exception exp)
                {
                    Console.WriteLine(exp.ToString());
                }
     
                return output;
            }
        }
    }
    So i guess my question is what is the correct http headers to use here and also which headers are compulsory and which are just optional?

    i would also like to use the ETag, Accept and Connection header(s) so any info you can supply on them would be greatly appreciated!

    Thanks in advance! =)
    Ollie
  • Oralloy
    Recognized Expert Contributor
    • Jun 2010
    • 988

    #2
    The basic server mechanism is fairly simple, no?

    A query consists of
    1) The basic query line (GET, POST, etc.)
    2) The headers (header: values)
    3) A blank line
    4) The body of the query (arbitrary, see Content-Type header)

    So your first parse of the query should give you that break down.

    The headers are unordered, so you can just put them into a map, and retrieve them at will. Do you know the strict specification for headers?

    If I remember correctly, the blank line and body are optional.

    If you have a failed parse, then your response looks something like this:
    Code:
    HTTP/1.1 400 Bad Request
    Connection: close
    Server: Jetty(6.1.16)
    The hard part comes with how you process after you parse the query components.

    First off, you have to sanity check the basic headers. If any are wrong, throw an error.

    Next, since the query is valid, you hand it off to the query processor.

    The query processor generates its response and hands it back to the main server.

    Then, the main server constructs the formatted response and sends it to the client.

    One really good way to test is to use Telnet to link to your server. You can try it fairly easily under windows; use: telnet www.microsoft.com 80

    So, all that said, where is your server breaking down?

    Comment

    • Ollie Shotton
      New Member
      • Jan 2011
      • 12

      #3
      Yer its all very simple which i why i was confused as to why it wasn't working so i asked here for some help.

      It was blank line that i had missing which was making it not work properly, thanks for your help! =)

      and i know about the bad request just i hadn't got round to doing that yet, was trying to make the damn thing work first!! =P

      Comment

      Working...