I'm creating a server using C# and I'm able to receive requests and return HTML, but I'm not sure what I have to do to send image files so they will display on the page.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Net.Sockets;
using System.Net;
using System.IO;
namespace Ambar
{
class Program
{
static void Main(string[] args)
{
TcpListener listener = new TcpListener(80);
listener.Start();
while (true)
{
Console.WriteLine("waiting for a connection");
TcpClient client = listener.AcceptTcpClient();
StreamReader sr = new StreamReader(client.GetStream());
StreamWriter sw = new StreamWriter(client.GetStream());
Console.WriteLine(client.GetStream().ToString());
try
{
string request = sr.ReadLine();
Console.WriteLine(request);
string[] tokens = request.Split(' ');
string page = tokens[1];
if (page == "/")
{
page = "/default.htm";
}
StreamReader file = new StreamReader("../../web" + page);
sw.WriteLine("HTTP/1.0 200 OK\n");
string data = file.ReadLine();
while (data != null)
{
sw.WriteLine(data);
sw.Flush();
data = file.ReadLine();
}
}
catch (Exception e)
{
sw.WriteLine("HTTP/1.0 404 OK\n");
sw.WriteLine("<H1> Future Site of Ambar Remake </H!>");
sw.Flush();
}
client.Close();
}
}
}
I'm able to host whatever HTML I want, but if I try to display an image like
<img src="picture.gif" alt="a picture" height="42" width="42">
I'm not sure how to host that image and have it displayed there.
I assume you are using web sockets.
You'll need to return the image as a base 64 encoded string, then use the
<img src ="data:image/png;base64," + base64ImageHere
Format
HTTP request and response header have two line breaks(\n) to divide Header part and content part.
for example:
(Request that requesting an image(image.gif) from server)
GET /image.gif HTTP/1.1
User-Agent: WebBrowser
Accept-Encoding: deflate,gzip
Connection: keep-alive
... and more headers if present ...
(Response for image request)
HTTP/1.1 200 OK
Content-Length: <Length_Of_Content>
Content-Type: image/gif
... and more headers if present ...
<Data_Of_Image>
As you can see, there's two line breaks(\n) between response header and contents.
So, you have to read files as byte array(byte[]). In this situation, you can easily read files using System.IO.File.ReadAllBytes(string).
Now, one more left. I told you read files as byte array, but there's no way to join string and byte[]. So you have to encode string to byte[] and join header bytes and content bytes.
+ We can't send byte array via StreamWriter so, we'll use NetworkStream.
Here's explanation:
NetworkStream ns = client.GetStream();
...
string[] tokens = request.Split(' ');
string page = tokens[1];
if (page == "/")
{
page = "/default.htm";
}
//StreamReader file = new StreamReader("../../web" + page);
byte[] file = null;
try { file = File.ReadAllBytes(#"../../web" + page); }
// In this 'catch' block, you can't read requested file.
catch {
// do something (like printing error message)
}
// We are not going to use StreamWriter, we'll use StringBuilder
StringBuilder sbHeader = new StringBuilder();
// STATUS CODE
sbHeader.AppendLine("HTTP/1.1 200 OK");
// CONTENT-LENGTH
sbHeader.AppendLine("Content-Length: " + file.Length);
// Append one more line breaks to seperate header and content.
sbHeader.AppendLine();
// List for join two byte arrays.
List<byte> response = new List<byte>();
// First, add header.
response.AddRange(Encoding.ASCII.GetBytes(sbHeader.ToString()));
// Last, add content.
response.AddRange(file);
// Make byte array from List<byte>
byte[] responseByte = response.ToArray();
// Send entire response via NetworkStream
ns.Write(responseByte, 0, responseByte.Length);
This is it. I hope you can understand my bad english :O.
Hope this help to you!
Related
I have a simple part of the code that creates a http listener for a specific url. Everything works perfectly, untill I turn on Xampp - Apache Web Server. At that moment, whenever I try to run the listener, I get Address already in use exeption.
I did some research and found a possible cause: I guess it won't work because Apache is listening to http port(idk if it is a proper term, it is what I got from running lsof-i:http command.), therefore my app cannot start the listener on http. But it is weird, since I have full url specified, so I suppose if request matches the url, Apache should stay away from it... Maybe I am wrong...
Does anyone know a solution how I could run Apache and my http listener at the same time?
Also I am running Debian 10 if it helps. Thanks in advance!
HttpListener listener2 = new HttpListener();
listener2.Prefixes.Clear();
listener2.Prefixes.Add("http://xxxx.xxxx.eu/");
listener2.Start();
LogWriteLine("http listener started listening to: " +listener2.Prefixes);
try
{
while (true)
{
HttpListenerContext context = listener2.GetContext();
HttpListenerRequest request = context.Request;
HttpListenerResponse response = context.Response;
System.IO.Stream body = request.InputStream;
System.Text.Encoding encoding = request.ContentEncoding;
System.IO.StreamReader reader = new System.IO.StreamReader(body, encoding);
if (!request.HasEntityBody)
{
LogWriteLine("No client data was sent with the request.");
Thread.Sleep(300);
}
if (request.ContentType != null)
{
LogWriteLine("Client data content type " + request.ContentType);
}
LogWriteLine("Client data content length " + request.ContentLength64);
LogWriteLine("Start of client data:");
string s = reader.ReadToEnd();
var bytes = default(byte[]);
using (var reader1 = new StreamReader(request.InputStream,
request.ContentEncoding))
{
text = reader1.ReadToEnd();
using (var memstream = new MemoryStream())
{
memstream.Position = 0;
reader1.BaseStream.CopyTo(memstream);
bytes = memstream.ToArray();
memstream.Position = 0;
Console.WriteLine("memstream length: " + memstream.Length);
}
Console.WriteLine("bytes:" + bytes.Length); //output: bytes: 0
}
LogWriteLine("End of client data:");
response.StatusCode = (int)HttpStatusCode.OK;
response.Close();
body.Close();
reader.Close();
}
}
catch (Exception ex)
{
Console.WriteLine(ex);
}
I am stuck with reading data from HttpListener. Data arrives, I verify it with request.ContentLength64 that is usually over 8000 and it increases as the server generates more and more data.
The server sends data as HTTP post and the content type is text/plain.
When I try to check whether streamreader got some data via its length attribute I get 0.
The code is a little bit messy as I was trying different ways to make it work but unfortunatelly I had no luck.
Does anyone got an idea what I'm doing wrong?
Thanks!
HttpListener listener2 = new HttpListener();
listener2.Prefixes.Clear();
listener2.Prefixes.Add("http://+:4200/");
listener2.Prefixes.Add("http://XXX.XXX.eu/");
listener2.Start();
LogWriteLine("http listener started listening to: " +listener2.Prefixes);
try
{
while (true)//change to match end check
{
LogWriteLine("http listener waiting");
HttpListenerContext context = listener2.GetContext();
LogWriteLine("http request arrived");
HttpListenerRequest request = context.Request;
// Obtain a response object.
HttpListenerResponse response = context.Response;
System.IO.Stream body = request.InputStream;
System.Text.Encoding encoding = request.ContentEncoding;
System.IO.StreamReader reader = new System.IO.StreamReader(body, encoding);
if (!request.HasEntityBody)
{
LogWriteLine("No client data was sent with the request.");
Thread.Sleep(300);
//return;
}
if (request.ContentType != null)
{
LogWriteLine("Client data content type " + request.ContentType);
}
LogWriteLine("Client data content length " + request.ContentLength64); //Works fine
LogWriteLine("Start of client data:");
// Convert the data to a string and display it on the console.
Console.WriteLine(body.CanSeek);
string s = reader.ReadToEnd();
var ahoj = new StreamReader(context.Request.InputStream).ReadToEnd();
Console.WriteLine("ahoj length " + ahoj.Length); //0
Console.WriteLine(s); //nothing
string text;
var bytes = default(byte[]);
using (var reader1 = new StreamReader(request.InputStream,
request.ContentEncoding))
{
text = reader1.ReadToEnd();
Console.WriteLine(text + text.Length); //output: 0
using (var memstream = new MemoryStream())
{
reader1.BaseStream.CopyTo(memstream);
bytes = memstream.ToArray();
}
Console.WriteLine("bytes:" + bytes.Length); //output: bytes: 0
}
LogWriteLine("End of client data:");
//write to console file
sw.Write(s);
body.Close();
reader.Close();
}
}
catch (Exception ex)
{
Console.WriteLine(ex);
}
I am trying to read url request that was sent via browser to my server. So basicly if I type http://localhost:8080/geoserver/ as my URL, server will respond and send a picture that is going to be displayed properly. Now I am trying to get the URL into string so if for example I type http://localhost:8080/geoserver/1234 I would be able to get 1234 out of my url string and then resize, rotate,.. my picture based on the input and display it. I tried with string my_url = listen.GetContext().toString(); but I am not getting URL that I've entered.
My code:
static void Main(string[] args)
{
HttpListener listen = new HttpListener();
string url = "http://localhost";
string port = "";
Console.Write("Nastavite port:");
port = Console.ReadLine();
url = url + ":" + port + "/geoserver/";
listen.Prefixes.Add(url);
try
{
listen.Start();
}
catch(Exception e)
{
Console.WriteLine("Ta port je zaseden");
Console.ReadKey();
Environment.Exit(0);
}
while (true)
{
Console.WriteLine("Cakam...");
HttpListenerContext kontekst = listen.GetContext();
string msg = "hello world";
// kontekst.Response.ContentLength64 = Encoding.UTF8.GetByteCount(msg);
kontekst.Response.StatusCode = (int)HttpStatusCode.OK;
using (Stream stream = kontekst.Response.OutputStream)
using (Image image = Image.FromFile("jpg.png"))
using (MemoryStream ms = new MemoryStream())
using (StreamWriter writer = new StreamWriter(stream))
{
image.Save(ms, System.Drawing.Imaging.ImageFormat.Jpeg);
string base64 = Convert.ToBase64String(ms.ToArray());
writer.WriteLine($"<html><img src=\"data: image / png; base64, {base64} \"></html>");
}
Console.WriteLine("Sporočilo poslano");
}
}
You need to get the URI from kontekst.Request.Url and parse out that value yourself to decide what you need to do.
I put url to browser's address bar and it downloads the zip file to HD. The size of zipped file is 386 bytes as written in its properties.
When I use UnZipFiles method to extract the file - it works.
But, I want to download programaticaly and extract it in memory. I use GetResultFromServer method to get zipped content. As shown in headers the size of the content is the same as the size of zipped file saved on HD:
content-disposition: attachment; filename=emaillog-xml.zip
Content-Length: 386
Cache-Control: private
Content-Type: application/zip
Date: Mon, 10 Sep 2012 08:28:28 GMT
Server: Microsoft-IIS/7.5
X-AspNet-Version: 4.0.30319
X-Powered-By: ASP.NET
My question is how to extract the content returned by GetResultFromServer?
I tried the following:
var ms = new MemoryStream(Encoding.Unicode.GetBytes(res))
var s = new ZipInputStream(ms);
but I get Unable to read from this stream.
UPDATED
I tried var zipStream = new System.IO.Compression.GZipStream(response.GetResponseStream(), CompressionMode.Decompress) but I get The magic number in GZip header is not correct error
Code
private string GetResultFromServer(ElasticLogParams elasticLogParams)
{
var webRequest = (HttpWebRequest)WebRequest.Create(url);
var response = webRequest.GetResponse();
using (var reader = new StreamReader(response.GetResponseStream()))
{
var res = reader.ReadToEnd();
var headers = response.Headers.ToString();
return res;
}
}
public static void UnZipFiles(string zippedFilePath, Stream stream = null)
{
var s = new ZipInputStream(stream ?? File.OpenRead(zippedFilePath));
ZipEntry theEntry;
while ((theEntry = s.GetNextEntry()) != null)
{
using (var streamWriter = File.Create(#"D:\extractedXML.xml"))
{
var size = 2048;
var data = new byte[size];
while (true)
{
size = s.Read(data, 0, size);
if (size > 0)
{
streamWriter.Write(data, 0, size);
}
else
{
break;
}
}
streamWriter.Close();
}
}
s.Close();
}
Give this a shot:
var response = webRequest.GetResponse() as HttpWebResponse;
var stream = response.GetResponseStream();
var s = new ZipInputStream(stream);
I believe you're very close and that you're using the right approach -- you can use this article to back that up -- their code is very similar.
I'm using http://dotnetzip.codeplex.com/
I've not used it to download stuff, but to extract stuff that people upload to my server. I assume it should work perfectly the other way round too.
I've tried the built-in zip from microsoft too, but also had issues. So I gave it up and switched.
I am writing a super tiny web server for educational purposes.
For the following code, if I request a html page containing an image, I cannot see the image in the browser. What am I doing wrong?
static void Main(string[] args)
{
TcpListener listener = new TcpListener(9999);
listener.Start();
while (true)
{
TcpClient client = listener.AcceptTcpClient();
string request = GetRequest(client.GetStream(),
client.ReceiveBufferSize);
WriteOutput(request, client.GetStream());
client.Close();
}
}
static void WriteOutput(string request, NetworkStream output)
{
try
{
string[] reqs = request.Split(' ');
WriteOutputHelper(output, reqs[1].Substring(1));
}
catch (Exception)
{
WriteOutputHelper(output, "404.html");
}
}
private static void WriteOutputHelper(NetworkStream output, string file)
{
byte[] statusLine = (new System.Text.ASCIIEncoding()).
GetBytes(GetStatusLine(file) + "\r\n\r\n");
output.Write(statusLine, 0, statusLine.Length);
byte[] ContentType =
(new System.Text.ASCIIEncoding()).GetBytes(GetContentType(file) +
"\r\n\r\n");
output.Write(ContentType, 0, ContentType.Length);
byte[] response = System.IO.File.ReadAllBytes("C:\\" + file);
output.Write(response, 0, response.Length);
output.Flush();
}
static string GetContentType(string fileName)
{
string i = "<META http-equiv=\"Content-Type\" content=\"";
if ((fileName.IndexOf(".htm") > -1) || (fileName.IndexOf(".html") > -1))
i = i + "text/html";
else if (fileName.IndexOf(".jpg") > -1)
i = i + "image/jpeg";
i = i + ";\">";
return i;
}
static string GetStatusLine(string fileName)
{
string i = "HTTP/1.0 ";
if (fileName.IndexOf("404") > -1)
return i + "404 Not Found";
else if (fileName.IndexOf("jpg") > -1)
return i + "302 Found";
return i + "200 OK";
}
static string GetRequest(NetworkStream reqStream,int bufSize)
{
byte[] bytesFrom = new byte[10025];
reqStream.Read(bytesFrom, 0, bufSize);
string request = System.Text.Encoding.ASCII.GetString(bytesFrom);
return request;
}
Edited:
static void imageTest(NetworkStream output)
{
byte[] fileContent = System.IO.File.ReadAllBytes("C:\\sachin.jpg");
string statusLine = "HTTP/1.0 200 OK" + System.Environment.NewLine;
string contentType = "Content-type: image/jpeg" + System.Environment.NewLine;
string contentLength = "Content-length: " + fileContent.Length + System.Environment.NewLine;
System.Text.UnicodeEncoding coding = new UnicodeEncoding();
byte[] headers = coding.GetBytes(statusLine + contentType + contentLength);
output.Write(headers, 0, headers.Length);
output.Write(fileContent, 0, fileContent.Length);
output.Flush();
}
For the code above, I am getting this error in fiddler.
The Server did not return properly formatted HTTP Headers. HTTP headers
should be terminated with CRLFCRLF. These were terminated with LFLF.
I am using Unicode encoding because I want to convert string to bytes and I only know to use encoding.
The response for a JPG must be just the HTTP header and then the contents of the JPEG, not any HTML around it.
Something like
HTTP/1.0 200 OK
Content-type: image/jpeg
Content-length: XXXXX
RAWJPEGDATA
Fill in XXXXX with the number of bytes in the Jpeg, and just output the raw JPEG data directly, without any encoding.
Use Fiddler or Firebug to help debug -- they show the exact requests/responses being sent.
It looks like you are sending a 302 Found status for jpeg files, which is meant for redirects. You need to send 200 OK like you do for the HTML file.
I think the problem is in the WriteOutputHelper and the GetContentTypeHelper methods.
The headers should not have \r\n\r\n, one should suffice, also, the GetContentTypeHelper method should return a header like:
Content-type: image/jpeg
Not a html <meta> element which is meant for (X)HTML content, not a HTTP header.
Have you thought about using cassini, It is open source under the project title of utildev. You can definately write your own but you can never cover all your bases. An off the hip guess of what the issue is that all the mime types are not supported by your lite web server.