How can I save http requests from applications in c#? - c#

When I connect my phone to iTunes it sends a request to a certain server so I have managed to divert to my server which I think I don't have the file or files that iTunes asks for but I would like to know what iTunes is requesting.
Here is my code
using System.Net.Sockets;
using System.Net;
using System.Threading;
using System.Text;
using System.Collections.Generic;
using System.IO;
namespace SimpleWebServer
{
class Server
{
/************************************\
* Acrobyte Http Web Server *
* Alexio Puk2sefu *
* www.acrobytemob.com *
* Alexiopuk2sefu#acrobytemob.com *
\************************************/
public bool running = false; // Is it running?
private int timeout = 8; // Time limit for data transfers.
private Encoding charEncoder = Encoding.UTF8; // To encode string
private Socket serverSocket; // Our server socket
private string contentPath; // Root path of our contents
// Content types that are supported by our server
// You can add more...
// To see other types: http://www.webmaster-toolkit.com/mime-types.shtml
private Dictionary<string, string> extensions = new Dictionary<string, string>()
{
//{ "extension", "content type" }
{ "htm", "text/html" },
{ "html", "text/html" },
{ "xml", "text/xml" },
{ "txt", "text/plain" },
{ "css", "text/css" },
{ "png", "image/png" },
{ "gif", "image/gif" },
{ "jpg", "image/jpg" },
{ "jpeg", "image/jpeg" },
{ "zip", "application/zip"},
{ "plist", "application/plist"},
{ "app", "application/app"},
{ "file", "application/file"}
};
public bool start(IPAddress ipAddress, int port, int maxNOfCon, string contentPath)
{
if (running) return false; // If it is already running, exit.
try
{
// A tcp/ip socket (ipv4)
serverSocket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
serverSocket.Bind(new IPEndPoint(ipAddress, port));
serverSocket.Listen(maxNOfCon);
serverSocket.ReceiveTimeout = timeout;
serverSocket.SendTimeout = timeout;
running = true;
this.contentPath = contentPath;
}
catch { return false; }
// Our thread that will listen connection requests and create new threads to handle them.
Thread requestListenerT = new Thread(() =>
{
while (running)
{
Socket clientSocket;
try
{
clientSocket = serverSocket.Accept();
// Create new thread to handle the request and continue to listen the socket.
Thread requestHandler = new Thread(() =>
{
clientSocket.ReceiveTimeout = timeout;
clientSocket.SendTimeout = timeout;
try { handleTheRequest(clientSocket); }
catch
{
try { clientSocket.Close(); } catch { }
}
});
requestHandler.Start();
}
catch{}
}
});
requestListenerT.Start();
return true;
}
public void stop()
{
if (running)
{
running = false;
try { serverSocket.Close(); }
catch { }
serverSocket = null;
}
}
private void handleTheRequest(Socket clientSocket)
{
byte[] buffer = new byte[10240]; // 10 kb, just in case
int receivedBCount = clientSocket.Receive(buffer); // Receive the request
string strReceived = charEncoder.GetString(buffer, 0, receivedBCount);
// Parse the method of the request
string httpMethod = strReceived.Substring(0, strReceived.IndexOf(" "));
int start = strReceived.IndexOf(httpMethod) + httpMethod.Length + 1;
int length = strReceived.LastIndexOf("HTTP") - start - 1;
string requestedUrl = strReceived.Substring(start, length);
string requestedFile;
if (httpMethod.Equals("GET") || httpMethod.Equals("POST"))
requestedFile = requestedUrl.Split('?')[0];
else // You can implement other methods...
{
notImplemented(clientSocket);
return;
}
requestedFile = requestedFile.Replace("/", "\\").Replace("\\..", ""); // Not to go back
start = requestedFile.LastIndexOf('.') + 1;
if (start > 0)
{
length = requestedFile.Length - start;
string extension = requestedFile.Substring(start, length);
if (extensions.ContainsKey(extension)) // Do we support this extension?
if (File.Exists(contentPath + requestedFile)) // If yes check existence
// Everything is OK, send requested file with correct content type:
sendOkResponse(clientSocket, File.ReadAllBytes(contentPath + requestedFile), extensions[extension]);
else
notFound(clientSocket); // We don't support this extension. We are assuming that it doesn't exist.
}
else
{
// If file is not specified try to send index.htm or index.html
// You can add more (for example "default.html")
if (requestedFile.Substring(length - 1, 1) != "\\")
requestedFile += "\\";
if (File.Exists(contentPath + requestedFile + "index.htm"))
sendOkResponse(clientSocket, File.ReadAllBytes(contentPath + requestedFile + "\\index.htm"), "text/html");
else if (File.Exists(contentPath + requestedFile + "index.html"))
sendOkResponse(clientSocket, File.ReadAllBytes(contentPath + requestedFile + "\\index.html"), "text/html");
else
notFound(clientSocket);
}
}
private void notImplemented(Socket clientSocket)
{
sendResponse(clientSocket, "<html><head><meta http-equiv=\"Content-Type\" content=\"text/html; charset=utf-8\"></head><body><h2>Atasoy Simple Web Server</h2><div>501 - Method Not Implemented</div></body></html>", "501 Not Implemented", "text/html");
}
private void notFound(Socket clientSocket)
{
sendResponse(clientSocket, "<html><head><meta http-equiv=\"Content-Type\" content=\"text/html; charset=utf-8\"></head><body><h2>Atasoy Simple Web Server</h2><div>404 - Not Found</div></body></html>", "404 Not Found", "text/html");
}
private void sendOkResponse(Socket clientSocket, byte[] bContent, string contentType)
{
sendResponse(clientSocket, bContent, "200 OK", contentType);
}
// For strings
private void sendResponse(Socket clientSocket, string strContent, string responseCode, string contentType)
{
byte[] bContent = charEncoder.GetBytes(strContent);
sendResponse(clientSocket, bContent, responseCode, contentType);
}
// For byte arrays
private void sendResponse(Socket clientSocket, byte[] bContent, string responseCode, string contentType)
{
try
{
byte[] bHeader = charEncoder.GetBytes(
"HTTP/1.1 " + responseCode + "\r\n"
+ "Server: Acrobyte Web Server\r\n"
+ "Content-Length: " + bContent.Length.ToString() + "\r\n"
+ "Connection: close\r\n"
+ "Content-Type: " + contentType + "\r\n\r\n");
clientSocket.Send(bHeader);
clientSocket.Send(bContent);
clientSocket.Close();
}
catch { }
}
}
}
So the request is coming to this server but iTunes says error and I simply would like to save that request and view it later

Related

C# TCP Socket Distinguish from different clients

I might have a pretty basic question for some of you.
I have created a one(server) to many(clients) relationship where in which server selects a client to send and receive data from and to.
My question is, how can I distinguish incoming data from the different clients? Would I have to simply indicate this in a buffer?
Currently My server listens, accepts and adds clients to a list clientList:
private void StartListen()
{
//Creating a TCP Connection and listening to the port
tcpListener = new TcpListener(System.Net.IPAddress.Any, 6666);
tcpListener.Start();
toolStripStatusLabel1.Text = "Listening on port 6666 ...";
int counter = 0;
appStatus = 0;
while (true)
{
try
{
client = tcpListener.AcceptTcpClient();
counter++;
clientList.Add(client);
IPEndPoint ipend = (IPEndPoint)client.Client.RemoteEndPoint;
//Updating status of connection
toolStripStatusLabel1.Text = "Connected from " + IPAddress.Parse(ipend.Address.ToString());
appStatus = 1;
th_inPutStream = new Thread(delegate () { inPutStream(client); });
th_inPutStream.Start();
th_checkConnection = new Thread(checkConnection);
th_checkConnection.Start();
}
catch (Exception err)
{
Cleanup_dep();
}
}
}
Now i assume if I want to send a message to a specific client, id select the client by clientList[i] and send data.
My question is, when data is available in the network stream to read, how can i know which client its coming from?
This is how I manage incoming data:
private void inPutStream(TcpClient client)
{
try
{
while (true)
{
NetworkStream networkstream = client.GetStream();
if (networkstream.DataAvailable == true)
{
int messageID = 0;
int messageSize = 0;
int bufferSize = 100;
//First retrieve size of header
byte[] fileSizeBytes = new byte[4];
int bytes = networkstream.Read(fileSizeBytes, 0, 4);
int dataLength = BitConverter.ToInt32(fileSizeBytes, 0);
//Read stream containing header with message details
byte[] header = new byte[dataLength];
int headerbyte = networkstream.Read(header, 0, dataLength);
string headerString = Encoding.ASCII.GetString(header, 0, headerbyte);
// Process Message information ie Message ID & Message Size
string[] headerSplit = headerString.Split(new string[] { "\r\n" }, StringSplitOptions.None);
Dictionary<string, string> headers = new Dictionary<string, string>();
foreach (string s in headerSplit)
{
if (s.Contains(":"))
{
headers.Add(s.Substring(0, s.IndexOf(":")), s.Substring(s.IndexOf(":") + 1));
}
}
//Fetch Message ID & Size
messageSize = Convert.ToInt32(headers["len"]);
messageID = Convert.ToInt32(headers["MsgId"]);
//Filter actions by Message ID
if (messageID == 1)//Machine info
{
string machineinfo = processMessage(messageSize, bufferSize, networkstream);
clientNames.Add(machineinfo.Split(new char[] { '\r', '\n' })[0]);
updateClientListUI();
}
if (messageID == 2)//CMD Commands
{
updateText(txtCmdConsole, processMessage(messageSize, bufferSize, networkstream));
}
}
}
}
catch (Exception err)
{
{
Cleanup_dep();
}
}
}
So if networkstream.DataAvailable == true then it reads, but how can i know from which stream?

TcpListener AcceptSocket() accepts two connections for each single GET request

I have this web server program up and running, using TcpListener. The problem is that for each get request made through web browser (or chrome Postman extension), it captures two requests.
namespace Server
{
class WebServer2
{
private TcpListener listener;
private int port = 8080;
public WebServer2()
{
try
{
listener = new TcpListener(IPAddress.Parse("127.0.0.1"), port);
listener.Start();
Console.WriteLine("Listening...");
//start the thread which calls the method 'StartListen'
Thread th = new Thread(new ThreadStart(StartListen));
th.Start();
}
catch (Exception e)
{
Console.WriteLine("An Exception Occurred While Listening: " + e.ToString());
}
}
//Recieve Request
public void StartListen()
{
int iStartPos = 0;
String sRequest;
String sRequestedFile;
String sResponse = "";
while (true)
{
//Accept a new connection
Socket socket = listener.AcceptSocket();
if (socket.Connected)
{
Console.WriteLine("\nClient Connected");
Console.WriteLine("----------------");
//Receive data from the client
Byte[] bReceive = new Byte[1024];
int i = socket.Receive(bReceive, bReceive.Length, 0);
//Convert Byte to String
string sBuffer = Encoding.ASCII.GetString(bReceive);
//Only GET Request is accepted
if (sBuffer.Substring(0, 3) != "GET")
{
Console.WriteLine("Not a Get Request.");
socket.Close();
continue;
}
// Look for HTTP request
iStartPos = sBuffer.IndexOf("HTTP", 1);
// Get the HTTP text and version e.g. it will return "HTTP/1.1"
string sHttpVersion = sBuffer.Substring(iStartPos, 8);
// Extract the Requested Type and Requested file/directory
sRequest = sBuffer.Substring(0, iStartPos - 1);
//If file name not provided
if (sRequest.IndexOf(".") < 1)
{
Console.WriteLine("File name not Provided!");
socket.Close();
continue;
}
//Extract the requested file name
iStartPos = sRequest.LastIndexOf("/") + 1;
sRequestedFile = sRequest.Substring(iStartPos);
Console.WriteLine("Requested File: " + sRequestedFile);
int iTotBytes = 0;
sResponse = "";
FileStream fs = new FileStream(sRequestedFile, FileMode.Open, FileAccess.Read, FileShare.Read);
BinaryReader reader = new BinaryReader(fs);
byte[] bytes = new byte[fs.Length];
int read;
while ((read = reader.Read(bytes, 0, bytes.Length)) != 0)
{
// Read from the file and write the data to the network
sResponse = sResponse + Encoding.ASCII.GetString(bytes, 0, read);
iTotBytes = iTotBytes + read;
}
reader.Close();
fs.Close();
SendHeader(sHttpVersion, "text/html", iTotBytes, " 200 OK", ref socket);
SendToBrowser(bytes, ref socket);
socket.Send(bytes, bytes.Length, 0);
socket.Close();
}
}
}
// Overloaded Function, takes string, convert to bytes and calls
// overloaded sendToBrowserFunction.
public void SendToBrowser(String sData, ref Socket socket)
{
SendToBrowser(Encoding.ASCII.GetBytes(sData), ref socket);
}
/// Sends data to the browser (client)
public void SendToBrowser(Byte[] bSendData, ref Socket socket)
{
int numBytes = 0;
try
{
if (socket.Connected)
{
if ((numBytes = socket.Send(bSendData, bSendData.Length, 0)) == -1)
Console.WriteLine("Socket Error");
}
else
Console.WriteLine("Connection Dropped!");
}
catch (Exception e)
{
Console.WriteLine("Error: {0} ", e);
}
}
// This function send the Header Information to the client (Browser)
public void SendHeader(string sHttpVersion, string sMIMEHeader, int iTotBytes, string sStatusCode, ref Socket socket)
{
String sBuffer = "";
Byte[] bSendData;
if (sStatusCode.Equals("404") || sStatusCode.Equals("400"))
{
sBuffer = sBuffer + sHttpVersion + sStatusCode + "\r\n";
sBuffer = sBuffer + "Server: MyServer\r\n";
sBuffer = sBuffer + "Content-Length: " + 0 + "\r\n\r\n";
bSendData = Encoding.ASCII.GetBytes(sBuffer);
SendToBrowser(bSendData, ref socket);
}
else
{
sBuffer = sBuffer + sHttpVersion + sStatusCode + "\r\n";
sBuffer = sBuffer + "Server: MyServer\r\n";
sBuffer = sBuffer + "Content-Type: " + sMIMEHeader + "\r\n";
sBuffer = sBuffer + "Accept-Ranges: bytes\r\n";
sBuffer = sBuffer + "Content-Length: " + iTotBytes + "\r\n\r\n";
bSendData = Encoding.ASCII.GetBytes(sBuffer);
SendToBrowser(bSendData, ref socket);
}
}
}
}
Single request made by chrome against http://localhost:8080/page1.html
Request made by Postman Extension
The funny thing is, everything works find when I send request through my client program (using TcpClient).
I tested your server and got similar results:
Chrome automatically asks for a favicon.ico file for every request. This generates the extra GET request to your server.
Firefox doesn't do this and simply generates one request per refresh.
Then there is a second problem I experienced, which is the one in your Postman screenshot.
Chrome (including the Postman Extension running inside it) reconnects
without sending anything, so the server "hangs" until you get a
response filled with \0 (nul-characters).
This is part of Chrome's prediction service to load subsequent requests faster. You could disable this behavior under Settings (advanced) > Privacy:
In your server implementation, this results in the "Not a Get Request" output if no subsequent GET request follows (instead, Chrome sends \0 to signal its not sending anything anyway).
Note: I didn't experience any of this in the actual Postman application.
While the server waits for chrome to send a request, it cannot service any other requests. To prevent this from happening, consider using an asynchronous approach.

Download binary file over HTTP

I need to download a binary file , uploaded via http post. I can not able to download file.
I can see the content of data but I'm not able to save into my local disk.
this is what i see in string
--fUYxo2BFe6N Content-Disposition: form-data; name="data"; filename="EVLD_1.4.36_16_0993_0_000AAE0E0109_2D8A145A040000CC_0E0B1B0F3B29_0008.akt" Content-Type: application/x-gzip
‹ òÖwTcÈ”cdäã–æ7´fàZÇÇÈÉÀÀüA Èåp’Y9,Lp%ì#1& ‹…Äg¬ ‚
,
"8€dÐDÁ
"x#/ˆàü B D‚!!Ä ƒ³e¹!ê™è›è˜™ƒ‘e+R9*ÌG[+‚´möÛÊ€äò0²ª2¬B† --fUYxo2BFe6N Content-Disposition: form-data; name="SehirID"
16 --fUYxo2BFe6N Content-Disposition: form-data; name="CihazTipiID"
64 --fUYxo2BFe6N Content-Disposition: form-data; name="CihazAltTipiID"
1 --fUYxo2BFe6N Content-Disposition: form-data; name="md5"
1FAFE4C67252889C75C526EA4313BE27 --fUYxo2BFe6N Content-Disposition: form-data; name="mac"
000AAE0E0109 --fUYxo2BFe6N--
This is my source code for listenint requests. I can handle de requests but I'm not able to save content into a file..
public class HttpProcessor
{
public TcpClient socket;
public HttpServer srv;
private Stream inputStream;
public StreamWriter outputStream;
public String http_method;
public String http_url;
public String http_protocol_versionstring;
public Hashtable httpHeaders = new Hashtable();
private static int MAX_POST_SIZE = 10 * 1024 * 1024; // 10MB
public HttpProcessor(TcpClient s, HttpServer srv)
{
this.socket = s;
this.srv = srv;
}
private string streamReadLine(Stream inputStream)
{
int next_char;
string data = "";
while (true)
{
next_char = inputStream.ReadByte();
if (next_char == '\n') { break; }
if (next_char == '\r') { continue; }
if (next_char == -1) { Thread.Sleep(1); continue; };
data += Convert.ToChar(next_char);
}
return data;
}
public void process()
{
// we can't use a StreamReader for input, because it buffers up extra data on us inside it's
// "processed" view of the world, and we want the data raw after the headers
inputStream = new BufferedStream(socket.GetStream());
// we probably shouldn't be using a streamwriter for all output from handlers either
outputStream = new StreamWriter(new BufferedStream(socket.GetStream()));
try
{
parseRequest();
readHeaders();
if (http_method.Equals("GET"))
{
handleGETRequest();
}
else if (http_method.Equals("POST"))
{
handlePOSTRequest();
}
}
catch (Exception e)
{
Console.WriteLine("Exception: " + e.ToString());
writeFailure();
}
outputStream.Flush();
// bs.Flush(); // flush any remaining output
inputStream = null; outputStream = null; // bs = null;
socket.Close();
}
public void parseRequest()
{
String request = streamReadLine(inputStream);
string[] tokens = request.Split(' ');
if (tokens.Length != 3)
{
throw new Exception("invalid http request line");
}
http_method = tokens[0].ToUpper();
http_url = tokens[1];
http_protocol_versionstring = tokens[2];
Console.WriteLine("starting: " + request);
}
public void readHeaders()
{
Console.WriteLine("readHeaders()");
String line;
while ((line = streamReadLine(inputStream)) != null)
{
if (line.Equals(""))
{
Console.WriteLine("got headers");
return;
}
int separator = line.IndexOf(':');
if (separator == -1)
{
throw new Exception("invalid http header line: " + line);
}
String name = line.Substring(0, separator);
int pos = separator + 1;
while ((pos < line.Length) && (line[pos] == ' '))
{
pos++; // strip any spaces
}
string value = line.Substring(pos, line.Length - pos);
Console.WriteLine("header: {0}:{1}", name, value);
httpHeaders[name] = value;
}
}
public void handleGETRequest()
{
srv.handleGETRequest(this);
}
private const int BUF_SIZE = 4096;
public void handlePOSTRequest()
{
// this post data processing just reads everything into a memory stream.
// this is fine for smallish things, but for large stuff we should really
// hand an input stream to the request processor. However, the input stream
// we hand him needs to let him see the "end of the stream" at this content
// length, because otherwise he won't know when he's seen it all!
Console.WriteLine("get post data start");
int content_len = 0;
MemoryStream ms = new MemoryStream();
if (this.httpHeaders.ContainsKey("Content-Length"))
{
content_len = Convert.ToInt32(this.httpHeaders["Content-Length"]);
if (content_len > MAX_POST_SIZE)
{
throw new Exception(
String.Format("POST Content-Length({0}) too big for this simple server",
content_len));
}
byte[] buf = new byte[BUF_SIZE];
int to_read = content_len;
while (to_read > 0)
{
Console.WriteLine("starting Read, to_read={0}", to_read);
int numread = this.inputStream.Read(buf, 0, Math.Min(BUF_SIZE, to_read));
Console.WriteLine("read finished, numread={0}", numread);
if (numread == 0)
{
if (to_read == 0)
{
break;
}
else
{
throw new Exception("client disconnected during post");
}
}
to_read -= numread;
ms.Write(buf, 0, numread);
}
ms.Seek(0, SeekOrigin.Begin);
// String s1 = Encoding.UTF8.GetString(ms.ToArray());
}
Console.WriteLine("get post data end");
srv.handlePOSTRequest(this, new StreamReader(ms));
}
private static Stream GetPostStream(string filePath, string boundary)
{
Stream postDataStream = new System.IO.MemoryStream();
//adding form data
string formDataHeaderTemplate = Environment.NewLine + "--" + boundary + Environment.NewLine +
"Content-Disposition: form-data; name=\"{0}\";" + Environment.NewLine + Environment.NewLine + "{1}";
//foreach (string key in formData.Keys)
//{
// byte[] formItemBytes = System.Text.Encoding.UTF8.GetBytes(string.Format(formDataHeaderTemplate,
// key, formData[key]));
// postDataStream.Write(formItemBytes, 0, formItemBytes.Length);
//}
//adding file data
FileInfo fileInfo = new FileInfo(filePath);
string fileHeaderTemplate = Environment.NewLine + "--" + boundary + Environment.NewLine +
"Content-Disposition: form-data; name=\"{0}\"; filename=\"{1}\"" +
Environment.NewLine + "Content-Type: application/vnd.ms-excel" + Environment.NewLine + Environment.NewLine;
byte[] fileHeaderBytes = System.Text.Encoding.UTF8.GetBytes(string.Format(fileHeaderTemplate,
"UploadCSVFile", fileInfo.FullName));
postDataStream.Write(fileHeaderBytes, 0, fileHeaderBytes.Length);
FileStream fileStream = fileInfo.OpenRead();
byte[] buffer = new byte[1024];
int bytesRead = 0;
while ((bytesRead = fileStream.Read(buffer, 0, buffer.Length)) != 0)
{
postDataStream.Write(buffer, 0, bytesRead);
}
fileStream.Close();
byte[] endBoundaryBytes = System.Text.Encoding.UTF8.GetBytes("--" + boundary + "--");
postDataStream.Write(endBoundaryBytes, 0, endBoundaryBytes.Length);
return postDataStream;
}
public void writeSuccess(string content_type = "text/html")
{
outputStream.WriteLine("HTTP/1.0 200 OK");
outputStream.WriteLine("Content-Type: " + content_type);
outputStream.WriteLine("Connection: close");
outputStream.WriteLine("");
}
public void writeFailure()
{
outputStream.WriteLine("HTTP/1.0 404 File not found");
outputStream.WriteLine("Connection: close");
outputStream.WriteLine("");
}
}
public abstract class HttpServer
{
protected int port;
TcpListener listener;
bool is_active = true;
public HttpServer(int port)
{
this.port = port;
}
public void listen()
{
listener = new TcpListener(port);
listener.Start();
while (is_active)
{
TcpClient s = listener.AcceptTcpClient();
HttpProcessor processor = new HttpProcessor(s, this);
Thread thread = new Thread(new ThreadStart(processor.process));
thread.Start();
Thread.Sleep(1);
}
}
public abstract void handleGETRequest(HttpProcessor p);
public abstract void handlePOSTRequest(HttpProcessor p, StreamReader inputData);
}
public class MyHttpServer : HttpServer
{
public MyHttpServer(int port)
: base(port)
{
}
public override void handleGETRequest(HttpProcessor p)
{
if (p.http_url.Equals("/Test.png"))
{
Stream fs = File.Open("../../Test.png", FileMode.Open);
p.writeSuccess("image/png");
fs.CopyTo(p.outputStream.BaseStream);
p.outputStream.BaseStream.Flush();
}
Console.WriteLine("request: {0}", p.http_url);
p.writeSuccess();
p.outputStream.WriteLine("<html><body><h1>test server</h1>");
p.outputStream.WriteLine("Current Time: " + DateTime.Now.ToString());
p.outputStream.WriteLine("url : {0}", p.http_url);
p.outputStream.WriteLine("<form method=post action=/form>");
p.outputStream.WriteLine("<input type=text name=foo value=foovalue>");
p.outputStream.WriteLine("<input type=submit name=bar value=barvalue>");
p.outputStream.WriteLine("</form>");
}
public override void handlePOSTRequest(HttpProcessor p, StreamReader inputData)
{
Console.WriteLine("POST request: {0}", p.http_url);
string data = inputData.ReadToEnd();
//SaveStreamToFile(inputData);
p.writeSuccess();
p.outputStream.WriteLine("<html><body><h1>test server</h1>");
p.outputStream.WriteLine("<a href=/test>return</a><p>");
p.outputStream.WriteLine("postbody: <pre>{0}</pre>", data);
}
public void SaveStreamToFile(Stream stream)
{
if (stream.Length == 0) return;
// Create a FileStream object to write a stream to a file
using (FileStream fileStream = System.IO.File.Create(#"C:/EmreDenemeHttp.txt", (int)stream.Length))
{
// Fill the bytes[] array with the stream data
byte[] bytesInStream = new byte[stream.Length];
stream.Read(bytesInStream, 0, (int)bytesInStream.Length);
// Use FileStream object to write to the specified file
fileStream.Write(bytesInStream, 0, bytesInStream.Length);
}
}
}
public class TestMain
{
public static int Main(String[] args)
{
HttpServer httpServer;
if (args.GetLength(0) > 0)
{
httpServer = new MyHttpServer(Convert.ToInt16(args[0]));
}
else
{
httpServer = new MyHttpServer(80);
}
Thread thread = new Thread(new ThreadStart(httpServer.listen));
thread.Start();
return 0;
}
}
If you mean you see this as string in your browser, the mime type sent by your server to your client may be wrong.
By default it is set to text/html.
It should be something like application/x-binary
or perhaps application/x-gzip
Check what mime type is fetched by your client when you display the page and act accordingly on your server.

Auto flush of tcp stream doesn't work

As you may see I work a little SMTP server written in C#.
I included whole code (one class is not included), but I hope you get good view of detail.
I am struggeling at the DATA post from the client, the problem is in my point of view the not working "Auto Flush".
The client sends to my server "DATA" to tell me to get ready to receive data for my email.
I need to answer "354 start mail input", which I do, my problem is:
After sending "354 start mail input" I need to receive the message from client in this funtion.
using System;
using System.Text;
using System.Net;
using System.Net.Sockets;
using System.Threading;
namespace FakeSMTP
{
public class SMTPServer //: IDisposable
{
TcpClient client;
NetworkStream stream;
System.IO.StreamReader reader;
System.IO.StreamWriter writer;
//public void Dispose()
//{
// writer.Dispose();
// reader.Dispose();
// stream.Dispose();
//}
public SMTPServer(TcpClient client)
{
this.client = client;
stream = client.GetStream();
reader = new System.IO.StreamReader(stream);
writer = new System.IO.StreamWriter(stream);
writer.NewLine = "\r\n";
writer.AutoFlush = true;
}
static void Main(string[] args)
{
TcpListener listener = new TcpListener(IPAddress.Loopback, 25);
listener.Start();
//using (SMTPServer handler = new SMTPServer(listener.AcceptTcpClient()))
while (true)
{
SMTPServer handler = new SMTPServer(listener.AcceptTcpClient());
Thread thread = new System.Threading.Thread(new ThreadStart(handler.Run));
thread.Start();
}
}
public void Run()
{
string sadress;
string radress;
string rserver;
bool auth = false;
writer.WriteLine("220 smtp.localsmtp.de ESMTP server ready");
for (string line = reader.ReadLine(); line != null; line = reader.ReadLine())
{
Console.Error.WriteLine("Read line {0}", line);
if (line.StartsWith("EHLO"))
{
writer.WriteLine("250-smtp.localsmtp.de");
//Auth ankuendigen
writer.WriteLine("250 AUTH PLAIN");
}
if (line.StartsWith("QUIT"))
{
writer.WriteLine("221 Bye Sweetie see ya");
client.Close();
}
#region auth
if (line.StartsWith("AUTH PLAIN"))
{
Console.WriteLine("client sendet Auth: " + line);
string [] pw = line.Split(new string[] { "PLAIN " }, StringSplitOptions.None);
byte[] bytes = Convert.FromBase64String(pw[1]);
string result = Encoding.BigEndianUnicode.GetString(bytes);
if (result == "12")
{
writer.WriteLine("235 2.7.0 Authentication successful");
auth = true;
}
else
{
Console.WriteLine("Falsche AUTH Daten");
writer.WriteLine("535 – Incorrect authentication data");
}
}
#endregion
#region sender
if (line.StartsWith("MAIL FROM") && auth == true)
{
string[] sadressa = line.Split(new string[] { "FROM:" }, StringSplitOptions.None);
sadress = sadressa[1];
//Absender
sadress = sadress.Replace("<","").Replace(">","");
//Debug
Console.WriteLine("Absender: " + sadress);
writer.WriteLine("250 OK");
}
#endregion
#region receiver
if (line.StartsWith("RCPT TO:") && auth == true)
{
string[] radressa = line.Split(new string[] { "RCPT TO:" }, StringSplitOptions.None);
radress = radressa[1];
//Empfänger
radress = radress.Replace("<", "").Replace(">", "");
if (samplesmtp.getMX.GetMXRecord(radress) != "invalid")
{
rserver = samplesmtp.getMX.GetMXRecord(radress);
Console.WriteLine("MX Record: " + rserver);
}
else
Console.WriteLine("ALARM");
//Debug
Console.WriteLine("Empfänger: " + radress);
writer.WriteLine("250 OK");
}
#endregion
#region data
if (line.StartsWith("DATA") && auth == true)
{
writer.WriteLine("354 start mail input");
var emailLine = reader.ReadLine();
while (!emailLine.Equals("."))
{
// add emailLine to the email body
string[] emailbody = new string[] {emailLine};
Console.WriteLine("Emailbody: " + emailbody[0]);
}
reader.Close();
writer.Close();
stream.Dispose();
writer.WriteLine("250 OK");
}
#endregion
}
}
}
}
Trying to call .Flush() manually in code doesn't change the problem at all. No effect.
In answer to your actual question you want to read all the lines until you receive a . on a line on it's own (see https://www.ietf.org/rfc/rfc2821.txt), something like this: -
var emailLine = reader.ReadLine();
while (!emailLine.Equals("."))
{
// add emailLine to the email body
emailLine = reader.readLine();
}
writer.WriteLine("250 OK");
reader.Close();
writer.Close();
stream.Dispose();
In response to your comment to mine:
public class SMTPServer : IDisposable
{
// all the other stuff
public void Dispose()
{
writer.Dispose();
reader.Dispose();
stream.Dispose();
}
}
calling code:
static void Main(string[] args)
{
TcpListener listener = new TcpListener(IPAddress.Loopback, 25);
listener.Start();
using (SMTPServer handler = new SMTPServer(listener.AcceptTcpClient()))
{
while (true)
{
Thread thread = new System.Threading.Thread(new ThreadStart(handler.Run));
thread.Start();
}
}
}

Downloading web site using sockets

I'm trying to download source of the site using sockets. Currently i can download headers and after that i just terminate connection because i don't know how long should I receive data. This is the code:
private void HandleConnect(SocketAsyncEventArgs e)
{
if (e.ConnectSocket != null)
{
// simply start sending
bool completesAsynchronously = e.ConnectSocket.SendAsync(e);
// check if the completed event will be raised.
// if not, invoke the handler manually.
if (!completesAsynchronously)
{
SocketAsyncEventArgs_Completed(e.ConnectSocket, e);
}
}
}
private void HandleReceive(SocketAsyncEventArgs e)
{
string responseL = Encoding.UTF8.GetString(e.Buffer, 0, e.Buffer.Length);
response += responseL;
temp += responseL;
string[] lines = Regex.Split(response, "\r\n\r\n");
if (lines.Length > 1 && header == "")
{
header = lines[0].ToString() + "\r\n";
lines[0] = "";
response = lines.ToString();
}
if (header == "")
{
bool completesAsynchronously = e.ConnectSocket.ReceiveAsync(e);
}
else
{
System.Windows.Deployment.Current.Dispatcher.BeginInvoke(delegate()
{
_callback(false, this);
});
}
}
I was trying to search for \r\n but it didn't help :/
Please help!
Thank you in advance :)
I use this code to send headers to the site and then read its content. I hope you find it useful.
ReadStateObject stateObject; //Info below
mytcpclient = new TcpClient();
mytcpclient.Connect(host, port);
mysocket = mytcpclient.Client;
SendHeader(mysocket);//Info below
ns = mytcpclient.GetStream();
if (ns.CanRead)
{
stateObject = new ReadStateObject(ns, 1024);
ns.BeginRead(stateObject.ReadBuffer, 0, stateObject.ReadBuffer.Length, new AsyncCallback(ReadCallBack), stateObject);
}
StateObject is small class used to represent the AsyncState object in BeginRead method:
class ReadStateObject
{
public NetworkStream Stream {get; set;}
public byte[] ReadBuffer;
public ReadStateObject(NetworkStream _stream, int bufferSize)
{
Stream = _stream;
ReadBuffer = new byte[bufferSize];
}
}
And this is a Callback Method used in BeginRead method.
private void ReadCallBack(IAsyncResult result)
{
ReadStateObject stateObject = (ReadStateObject)result.AsyncState;
NetworkStream myNetworkStream = stateObject.Stream;
int numberofbytesread = 0;
StringBuilder sb = new StringBuilder();
numberofbytesread = myNetworkStream.EndRead(result);
sb.Append(Encoding.ASCII.GetString(stateObject.ReadBuffer, 0, numberofbytesread));
/*It seems, if there is no delay, the DataAvailable may not be true even when there are still data to be received from the site, so I added this delay. Any suggestions, how to avoid this are welcome*/
Thread.Sleep(500);
while (myNetworkStream.DataAvailable)
{
byte[] mydata = new byte[1024];
numberofbytesread = myNetworkStream.Read(mydata, 0, mydata.Length);
sb.Append(Encoding.ASCII.GetString(mydata, 0, numberofbytesread));
}
Console.Writeln(sb.ToString());
mytcpclient.Close();
}
And this is where Headers are sent to the site
public void SendHeader(Socket mySocket)
{
String sBuffer = "";
sBuffer = sBuffer + "GET /"+pathquery+" HTTP/1.1" + "\r\n";
sBuffer = sBuffer + "Host: "+ hostname + "\r\n";
sBuffer = sBuffer + "Content-Type: text/html\r\n";
sBuffer = sBuffer + "\r\n";
Byte[] bSendData = Encoding.ASCII.GetBytes(sBuffer);
mySocket.Send(Encoding.ASCII.GetBytes(sBuffer), Encoding.ASCII.GetBytes(sBuffer).Length, 0);
}
Maybe, you should use WebClient or HttpWebRequest instead of sockets.
Using sockets and interpreting Http protocol can be painful.

Categories

Resources