Search code examples
c#httpwebserverpng

Sending a PNG using HTTP in C#


I'm developing my own simple webserver in C#, and I have normal html files and subfolders etc in place and working fine... however my issue lies with sending PNG files.

Once the browser has made the HTTP request and my other code has done its magic, I need to send a response header. Here is my code to do this:

        else if (URL.EndsWith(".ico") || URL.EndsWith(".png"))
        {
            if (File.Exists(Program.Start_Directory + URL))
            {
                byte[] ImgFile = File.ReadAllBytes(Program.Start_Directory + URL);
                sw.Write("HTTP/1.0 200 OK\r\n");
                sw.Write("Content-Type: image/png\r\n");
                sw.Write("Content-Length: " + ImgFile.Length + "\r\n");
                sw.Write("\r\n");
                sw.Write(ImgFile);
            }
            else
            {
                FileNotFoundPage(sw);
            }
        }

sw in this instance being the StreamWriter for the socket connection to the browser.

When I run this, the browser screen goes black like it usually does when its about to load an image, but no image loads and the spinning loading wheel remains spinny indefinitely.

How can I get this to work? Thanks.


Solution

  • Things get messy when you use a StreamWriter (which is designed to write strings with a specific Encoding to a stream) with binary data.

    It looks like you are invoking this overload of StreamWriter.Write with the belief that it writes the bytes verbatim to the output stream. The docs state that this overload actually...

    Writes the text representation of an object to the text string or stream by calling the ToString method on that object

    You have two options. Carry on using StreamWriter and Flush, then write the binary data directly to the underlying stream:

    byte[] ImgFile = File.ReadAllBytes(Program.Start_Directory + URL);
    sw.Write("HTTP/1.0 200 OK\r\n");
    //...etc
    sw.Flush();
    sw.BaseStream.Write(ImgFile,0,ImgFile.Length);
    

    or just do everything in bytes:

    var sb=new StringBuilder();
    sb.AppendLine("HTTP/1.0 200 OK");
    //...etc
    var headerBytes = Encoding.ASCII.GetBytes(sb.ToString());
    Stream str = iGotTheStreamFromSomewhere;
    str.Write(headerBytes,0,headerBytes.Length);
    str.Write(ImgFile,0,ImgFile.Length);