Establishing a simple websocket handshake - c#

Client:
<script type="text/javascript">
var socket = new WebSocket('ws://localhost:8183/websession');
socket.onopen = function () {
alert('handshake successfully established. May send data now...');
};
socket.onclose = function () {
alert('connection closed');
};
</script>
server:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Net.Sockets;
using System.Net;
using System.IO;
class Program
{
static void Main(string[] args)
{
var listener = new TcpListener(IPAddress.Loopback, 8183);
listener.Start();
using (var client = listener.AcceptTcpClient())
using (var stream = client.GetStream())
using (var reader = new StreamReader(stream))
using (var writer = new StreamWriter(stream))
{
writer.WriteLine("HTTP/1.1 101 Web Socket Protocol Handshake");
writer.WriteLine("Upgrade: WebSocket");
writer.WriteLine("Connection: Upgrade");
writer.WriteLine("WebSocket-Origin: http://localhost:8092");
writer.WriteLine("WebSocket-Location: ws://localhost:8183/websession");
writer.WriteLine("");
}
listener.Stop();
}
}
the problem is that the connection is never established and the onopen function is never called what may be the problem ?

Firstly, your "server" seems to be sending the "client" part of the handshake. Secondly, StreamReader and StreamWriter will not help you much; frankly, you would do well just to use the Stream.
Now, the actual handshake is complicated; both client and server need to prove to each-other than they are actually talking web-sockets, and not HTTP. The exact nature of this depends on the version of the protocol you are trying to support (or multiple protocols), but the server is required to perform a maths calculation based on the headers that the client sends; the server sends the answer back in its headers, and this checks that they are talking the same language. Note that this is not a security step: it is a sanity protection step. This is all described in the specification, but an example request / response pair is (from that document):
GET /chat HTTP/1.1
Host: server.example.com
Upgrade: websocket
Connection: Upgrade
Sec-WebSocket-Key: dGhlIHNhbXBsZSBub25jZQ==
Origin: http://example.com
Sec-WebSocket-Protocol: chat, superchat
Sec-WebSocket-Version: 13
And:
HTTP/1.1 101 Switching Protocols
Upgrade: websocket
Connection: Upgrade
Sec-WebSocket-Accept: s3pPLMBiTxaQ9kYGzzhZRbK+xOo=
Sec-WebSocket-Protocol: chat
After which, it drops from HTTP into web-socket protocol, which is binary and unrelated to HTTP. For info, Sec-WebSocket-Accept is the result of the maths calculation, based on the client's Sec-WebSocket-Key.
The next bit of code that you will need is frame support. Again - see the specification. Also keep in mind that this specification is just version 13. If you want to support all clients, you might need to check the older specifications too (there are some subtle tweaks, except for the original original protocol, which was radically different and will require completely different code).
Before writing all this, you might want to look into whether a pre-existing library would be more practical. Windows 8 (and similar versions of server) include web-socket supprt direct in HTTP.SYS, with full support in .NET.

Related

How do I enable https with httplistener?

I am trying to create a simple https server in c# in a Unity3D game, to be accessed through a web browser. I've created a server cert and key with openssl, but I can't find a multi-platform way to pass the cert to the server without any additional configuration outside the code.
Most of the info I've been able to find falls into these categories:
Uses SslStream, but that seems to only be relevant for TcpListener (and I want something higher level that can serve webpages)
Requires external Windows-only tools like httpcfg that I'd prefer not to use
Programmatically or manually installing certs in certificate stores, which seems to require either the program or the user to have admin/root privileges
I know in python you do something like:
ssl.wrap_socket (httpd.socket, certfile='./server-crt.pem', keyfile='./server-key.pem', server_side=True)
...but there doesn't seem to be an equivalent in c# for httplistener, or in system.security.securitymanager or anything. I assume/hope that I'm just missing something obvious here.
For what it's worth, here's what I have so far, which is just the MSDN httplistener example put in a Unity script:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using System;
using System.Net;
public class SimpleListenerExample : MonoBehaviour {
// This example requires the System and System.Net namespaces.
public static void StartServer(string[] prefixes)
{
if (!HttpListener.IsSupported)
{
Console.WriteLine("Windows XP SP2 or Server 2003 is required to use the HttpListener class.");
return;
}
// URI prefixes are required,
// for example "http://contoso.com:8080/index/".
if (prefixes == null || prefixes.Length == 0)
throw new ArgumentException("prefixes");
// Create a listener.
HttpListener listener = new HttpListener();
// Add the prefixes.
foreach (string s in prefixes)
{
listener.Prefixes.Add(s);
}
/* and here's the part where I would load the server certificate ...somehow */
listener.Start();
Console.WriteLine("Listening...");
// Note: The GetContext method blocks while waiting for a request.
HttpListenerContext context = listener.GetContext();
HttpListenerRequest request = context.Request;
// Obtain a response object.
HttpListenerResponse response = context.Response;
// Construct a response.
string responseString = "<HTML><BODY> Hello world!</BODY></HTML>";
byte[] buffer = System.Text.Encoding.UTF8.GetBytes(responseString);
// Get a response stream and write the response to it.
response.ContentLength64 = buffer.Length;
System.IO.Stream output = response.OutputStream;
output.Write(buffer, 0, buffer.Length);
// You must close the output stream.
output.Close();
listener.Stop();
}
// Use this for initialization
void Start () {
String[] prefixes = { "http://*:8089/", "https://*:8443/" };
StartServer(prefixes);
}
// Update is called once per frame
void Update () {
}
}
If you came here from Google trying to find information on HttpListener in Mono and SSL, you will find more pertinent information on this related question:
Mono HttpListener client certificate
The OPs originally desire is a simple web server without any platform-specific configuration. So far, the only library I've found that supports an approach that avoids platform configuration is Ceen HTTPd.
There was a discussion about Ceen from a poster with a similar need here:
https://softwarerecs.stackexchange.com/questions/52304/net-library-for-running-an-embedded-selfhosted-light-web-server-from-c-with-ss

C# Service Client - Transfer-Encoding: Chunked

I'm currently trying to fix my SOAP-Client in C#, but got somehow stuck with the Transfer-Encoding. I'm more or less a newbie to C#, so it's completly possible that im just missing something minor here.
I consumed a SOAP service from our local Tomcat Server following this: https://web.archive.org/web/20180506023052/http://www.csharptutorial.in/37/csharp-net-how-to-consume-a-web-service-in-csharp-net-visual-studio-2010
My current code:
using System;
using ConsoleApp1.Lims;
namespace ConsoleApp1
{
class Program
{
static void Main(string[] args)
{
LimsZugriffService client = new LimsZugriffService();
// FunktionsErgebnis response = client.connect();
// Console.WriteLine("Connect" + response.meldung);
String[] bond = new String[] { "versuch.auftrag.nr=2014/0031" };
String[] bondFail = new String[] { "abc" };
VersuchsschrittErgebnis reponseVersuch = client.ermittleVersuchsschritte(bond);
Console.WriteLine(reponseVersuch.ermittelteVersuchsschritte.Length);
Console.WriteLine(reponseVersuch.meldung);
}
}
}
After some testing I found out, that something does not work as intended. My Response-Array of <ermittelteVersuchsschritte> seems to be empty, while the "control"-Flags are parsed normally.
I captured the traffic between client and server to figure out what was wrong and it was actually completly there. Just chunked into 8192 Byte blocks.
Could it be, that the C# implementation of the WebClient got some problems with Transfer-Encoding: Chunked?
After googling for some hours i could not find a satisfiying solution to this issue. I hope somebody, who knows C# and WebServices better than me has the answer.
For the sake of completeness:
My WSDL
My Traffic - Request->Response
After some researching, trial and error and much time I finally figured out my mistake.
C# seems not to have a problem with the Transfer-Encoding: Chunked
The mistake was on the service side. The consumed wsdl was generated from java code with the help of Axis(the first Axis not Axis2). Axis generated a wsdl 1.0 while C# seems to expect wsdl 2.0. So in the end, the XML-structure described in the wsdl was flawed and could not be automatically consumed.
We fixed this problem by switching from Axis to Apache CXF. The newly generated wsdl was than consumed without a problem at our C# - client side.

How do I send a file on a self hosted web API and process it on the server?

I have a self hosted web api using Owin and Katana. I would like to send files (can be pretty large, a few hundred MB) from a sample client, and would like to save these files on the server's disk. Currently just testing the server on my local machine.
I have the following on the test client's machine (it says image here, but it's not always going to be an image):
using System;
using System.IO;
using System.Net.Http;
class Program
{
string port = "1234";
string fileName = "whatever file I choose will be here";
static void Main(string[] args)
{
string baseAddress = "http://localhost:" + port;
InitiateClient(baseAddress);
}
static void InitiateClient(string serverBase)
{
Uri serverUri = new Uri(serverBase);
using(HttpClient client = new HttpClient())
{
client.BaseAddress = serverUri;
HttpResponseMessage response = SendImage(client, fileName);
Console.WriteLine(response);
Console.ReadLine();
}
}
private static HttpResponseMessage SendImage(HttpClient client, string imageName)
{
using (var content = new MultipartFormDataContent())
{
byte[] imageBytes = System.IO.File.ReadAllBytes(imageName);
content.Add(new StreamContent(new MemoryStream(imageBytes)), "File", "samplepic.png");
client.DefaultRequestHeaders.Accept.Add(new System.Net.Http.Headers.MediaTypeWithQualityHeaderValue("multipart/form-data"));
return client.PostAsync("api/ServiceA", content).Result;
}
}
First, is this the right way of sending a file using POST?
And now here is where I'm really lost. I am not sure how to save the file I receive in the Post method of my ServiceAController which inherits ApiController. I saw some other examples which used HttpContext.Current, but since it's self hosted, it seems to be null.
I would split files into chunks before uploading. 100 Mb is a bit large for single HTTP POST request. Most of web servers also have certain limit on HTTP request size.
By using chunks you won't need to resend all data again if connection times out.
It should not matter whether you use self hosting or IIS, and whether it is an image file or any type of file.
You can check my answer that will give you simple code to do so
https://stackoverflow.com/a/10765972/71924
Regarding size, it is definitely better to chunk if possible but this gives more work for your clients (unless you also own the API client code) and for you on the server as you must rebuild the file.
It will depend if all files will be over 100MB or if only few. If they are consistently large, I would suggest to look for http byte range support. This is part of the http standard and I am sure you can find somebody who implemented it using WebAPI

HTTP over UDP adapter for Web API

I need to send some data from mobile clients to an ASP.NET ApiController. I cannot wait for an connection to be established (and I don't rely on the data to arrive), so I thought UDP is the way to go. On the server I need to listen on a UDP endpoint and redirect the request to my default HTTP endpoint.
This is what I have so far (shortened):
public class HttpOverUdpAdapter
{
public static UdpClient UpdListener;
public static void Start(int udpPort, tcpPort)
{
UpdListener = new UdpClient(udpPort);
new Thread(() =>
{
while (true)
{
IPEndPoint endpoint = new IPEndPoint(IPAddress.Any, udpPort);
byte[] bytes = UpdListener.Receive(ref endpoint);
TcpClient client = new TcpClient();
client.Connect(IPAddress.Loopback, tcpPort);
using (NetworkStream stream = client.GetStream())
{
stream.Write(bytes, 0, bytes.Length);
}
}
}).Start();
}
}
I get the following error when no matter what port I use:
System.Net.Sockets.SocketException: Only one usage of each socket address (protocol/network address/port) is normally permitted.
Apart from that, is this going to work out at all? Is it correct to start it in Application_Start()?
Remark: WCF is no alternative.
There is no such thing as "I don't rely on the data to arrive" with HTTP. HTTP consists of requests and responses, which are usually big enough so that multiple IP packets are needed. UDP does neither guarantee the delivery nor the order of the packets, so you might end up with corrupt requests which might result in no response (which might be ok for you) or in a response for another web resource (which is probably not ok). Also, the response can be corrupt too in an unpredictable way (which is probably not ok for you).
If you would a need a more reliable transport you would add a reliability layer on top of the UDP tunnel, which is neither simpler nor faster than simply using TCP directly.

how to send POST without waiting response C#

how to send POST without waiting response in C#?
How can I do it?
Help please!
Use one of the asynchronous methods in the WebClient class, for example UploadStringAsync.
The corresponding event (UploadStringCompleted for the example) will be triggered when the post is completed (or fails), but you don't have to hook up any handler for the event. You might want to do that, however, to check if there was any error.
An HTTP session is just a standard TCP session, and a POST is just a properly formatted piece of data that meets the HTTP specification. You can open a TCP connection to the web server and send a POST request and then close the TCP connection. You can check the HTTP specification (RFC 2616) to learn how to properly format a POST. You can find it at: http://www.w3.org/Protocols/rfc2616/rfc2616.html
A very basic POST would be sending the following over a TCP connection:
POST / HTTP/1.1
Host: www.thehost.com
Content-Length: 3
Content-Type: application/x-www-form-urlencoded
Hi!
Substituting the content, and the corresponding length with whatever you want to send, changing the / to the correct path and putting the hostname or IP of the host at Host:... and connecting the TCP session to that host of course.
A very very basic example:
using System.Net;
using System.Net.Sockets;
static void Main(string[] args)
{
string Hostname = "www.website.com";
TcpClient Client = new TcpClient(Hostname, 80);
Client.Client.Send(new ASCIIEncoding().GetBytes("POST / HTTP/1.1\nHost: "+Hostname+"\nConnection: close\n\n"));
Client.Close();
}
Changing www.website.com to the correct hostname (and the port if required).
UploadValuesAsync looks like a more complete solution, using something like this:
using (var client = new WebClient())
{
var values = new NameValueCollection();
// add values...
client.UploadValuesAsync(new System.Uri(rawUrl), "POST", values);
}
However note that I haven't tested this code as I was trying to solve a slightly different problem.
var wc = new WebClient();
wc.Headers["Content-type"] = "application/x-www-form-urlencoded";
wc.UploadStringAsync(uri, data);
wc.UploadStringCompleted += (sender, e) =>
{
// completed
};

Categories