Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

C# How do you send a file via TCP for HTTP?

Tags:

c#

tcplistener

The issue I'm currently facing is that I'm unable to get my C# program to write the file I want to send in the response (I'm writing the bytes of the file) and have a valid HTTP response, the browser I'm testing it with is saying ERR_INVALID_HTTP_RESPONSE if I have appended the file to the response.

Originally I was using a HttpListener but this was requiring me to run my IDE as admin every time so I decided to move away from it and start using a TcpListener.

This is just a simple web server that is running entirely off of C# and utilizes the TcpListener from System.Net. So far I've tried using the BaseStream from the StreamWriter to write the bytes of the file into the response.

I have been searching around to look for other ways to send a file via TCP / HTTP however it seems two things are apparent, its not brilliantly documented on how to properly do it and nobody seems to have asked the same question for this specific scenario.

So far the code that handles the response to the incoming connection is as follows.

      StreamReader sr = new StreamReader(client.GetStream());
      StreamWriter sw = new StreamWriter(client.GetStream());
      string request = sr.ReadLine();
      if (request != null) {
        //byte[] testData = Encoding.UTF8.GetBytes("Test");
        string[] tokens = request.Split(" ");
        try {
          FileInfo file = files[tokens[1]];
          byte[] fileBytes = File.ReadAllBytes(file.FullName);
          sw.WriteLine("HTTP/1.0 200 OK\n");
          sw.BaseStream.Write(fileBytes, 0, fileBytes.Length);
          sw.Flush();
        } catch {
          sw.WriteLine("HTTP/1.0 404 OK\n");
          sw.Write("<h1>Error 404</h1><p>The file you were looking for does not exist</p>");
          sw.Flush();
        }
      }
      client.Close();

The expected result is that the browser will show the image much like you'd see from an imgur link, basically the same format as I will use to show the screenshot of the current result is the expected result.

image taken from https://i.imgur.com/pxONnIP.png

like image 651
AlexJBallz Avatar asked May 14 '19 13:05

AlexJBallz


1 Answers

HTTP dictates that initial lines and headers should end in CRLF (not LF), and that a double CRLF should separate initial lines and headers from the response body.

Here's a super-handy quick-guide to the HTTP protocol:

https://www.jmarshall.com/easy/http/

You'll also probably need to flush your StreamWriter before you switch from operating over the StreamWriter to operating over it's base stream.

sw.Write("HTTP/1.0 200 OK\r\n\r\n");
sw.Flush(); //  <-- HERE
sw.BaseStream.Write(fileBytes, 0, fileBytes.Length);

I'd also avoid WriteLine as the line endings are not guaranteed to be the same across all platforms.

like image 79
spender Avatar answered Sep 18 '22 05:09

spender