How to inject Http Parser into OWIN Self host server - c#

I have http clients that are sending "POST" requests with no contents which cause the selfhost server to throw http 411 error , the http clients are for customers that it is not a solution to modify them , so the only way to modify my server to not throw this error when "POST" request arrive without content .
it seem it is happening in the low level , no attribute or filter or even app.Use worked to catch the request before the error get thrown
it mostly happening at the next level when TCP content get converted to HTTP request.
So basically I am looking for the point when before the server parse the TCP contents into HTTP request
static void Main(string[] args)
{
var baseAddress = new Uri("http://localhost:8073");
var config = new HttpSelfHostConfiguration(baseAddress);
config.Routes.MapHttpRoute("default", "{controller}");
using (var svr = new HttpSelfHostServer(config))
{
svr.OpenAsync().Wait();
Console.WriteLine("Press Enter to quit.");
Console.ReadLine();
}
}

It turned out the HTTP parser is not inject-able, it is kind of limitation in my openion to any http server , as the trip of data from TCP client until it get converted to HTTP request is black boxed at least in OWIN self host server

Related

How to change http.sys web server response when maxconnection limit reached

We are using http sys web server to host web api service. Business requires to limit maximum number of concurrent connections. MaxConnections configuration property used for that purpose:
services.Configure<HttpSysOptions>(options =>
{
options.MaxConnections = Configuration.GetValue<long?>("MaxConnections");
});
But in case when concurrent connection limit reached all new connections got dropped on a socket level. Is it possible to change this behaviour so server accepts the request and returns 4xx or 5xx response to the client?
I have finally managed to find a solution: there is Http503Verbosity property in options. By default it is set to Http503VerbosityLevel.Basic but if to change it to Http503VerbosityLevel .Limited or Http503VerbosityLevel.Full 503 response will be returned for requests above limit. So my code looks like this now:
services.Configure<HttpSysOptions>(options =>
{
options.MaxConnections = Configuration.GetValue<long?>("MaxConnections");
options.Http503Verbosity = Http503VerbosityLevel.Full;
});

SSL TLS communication in c# with self signed certificate not working

I have a .pem certificate file which is used to communicate between two servers. For communication I have written a program in C# like this:
var client = new RestClient("https://aaaaa.com:1111");
client.ClientCertificates = new X509CertificateCollection();
client.ClientCertificates.Add(new X509Certificate(#"C:\Users\aaa\Desktop\bbb.pem"));
var request = new RestRequest("/qqq/www", Method.POST);
request.AddJsonBody(new { create = new { msgBdy="Test" } });
var response = client.Execute(request);
Console.WriteLine(response.StatusCode);
//The underlying connection was closed: An unexpected error occurred on a send.
When I post the request through SoapUI it goes through, but when I try to send it through Postman or the above C# program it doesn't.
Screenshot from wireshark is below:
The change cipher spec event is called for the successful API call but through postman and c# application this event is never called.
I have tried to do this as explained in this article as well https://www.codeproject.com/Articles/326574/An-Introduction-to-Mutual-SSL-Authentication but that also didn't work.
How can I fix this issue.

.Net HttpListener.GetContext() gives "503 Service Unavailable" to the client

I am trying to write a very very simple custom Http server in C#.
The code to achieve a connection is as simple as .Net offers it:
// get our IPv4 address
IPAddress[] localIPs = Dns.GetHostAddresses(Dns.GetHostName());
IPAddress theAddress = localIPs.Where(ip => ip.AddressFamily == AddressFamily.InterNetwork).FirstOrDefault();
// Create a http listener.
var listener = new HttpListener();
string myUrlPrefix = $"http://{theAddress.ToString()}:{port}/MyService/";
listener.Prefixes.Add(myUrlPrefix);
Console.WriteLine($"Trying to listen on {myUrlPrefix}");
listener.Start();
Console.WriteLine("Listening...");
HttpListenerContext context = null;
try
{
context = listener.GetContext();
}
catch(Exception ex)
{
Console.WriteLine(ex.Message);
}
HttpListenerRequest request = context.Request;
When running this, GetContext() blocks, never returns and does not throw an exception.
listener.Start() works -- the URL is properly reserved for the correct user with 'netsh http add urlacl...'., else Start() would throw. The URL is also only reserved once.
I can see with netstat -na that the port is being listened on.
I am trying to access this with either a browser or with the cygwin implementation of wget. Both give me "ERROR 503: Service Unavailable.".
Here is the wget output:
$ wget http://127.0.0.1:45987/MyService/
--2016-03-06 14:54:37-- http://127.0.0.1:45987/MyService/
Connecting to 127.0.0.1:45987... connected.
HTTP request sent, awaiting response... 503 Service Unavailable
2016-03-06 14:54:37 ERROR 503: Service Unavailable.
This means that the TCP connection gets established, yet HttpListener.GetContext() does not bother to service the request and give me the context, it also doesn't bother to at least throw an exception to tell me what's wrong. It just closes the connection. From the debug output, it doesn't even have a First-Chance exception inside that it would catch itself.
I have searched the Net and Stackoverflow up and down and don't find anything useful.
There are no errors in the Windows Event log.
This is Windows 10 Pro and Microsoft Visual Studio Community 2015
Version 14.0.23107.0 D14REL with Microsoft .NET Framework Version 4.6.01038.
It may be worth mentioning that I have also tested this with all firewalls off, still the same result.
Does anyone have any idea what could be going wrong in the GetContext() and how I could debug or solve this?
======
EDIT: I have enabled .Net Framework source stepping and have stepped into GetContext(). The blocking and refusal to service http requests happens in something called "UnsafeNclNativeMethods.HttpApi.HttpReceiveHttpRequest" which, I guess, might be the native HttpReceiveHttpRequest method documented at https://msdn.microsoft.com/en-us/library/windows/desktop/aa364495(v=vs.85).aspx . So it's the native API that is refusing my request.
I just had the same problem, and it was caused by a URL ACL.
From an elevated command prompt
netsh http show urlacl will show all URL ACLs
netsh http delete urlacl http://+:1234/ will delete the URL ACL with the URL http://+:1234/
netsh http add urlacl url=http://+:1234/ user=Everyone will add a URL ACL that any local user can listen on (normally this should use the network service account)
This URL needs to match the prefix in your HttpListener.
If you're only listening on localhost, you don't need a URL ACL.
Normally not having the correct the URL ACL results in a permissions error when starting the listener. I'm not sure what the specific situation is that causes it to get past this but then return 503 Service Unavailable on GetContext.
I haven't found a solution, but a workaround.
Interestingly, if I go a level deeper and use a plain TcpListener, I have no problem receiving the request as plain text.
// Create a Tcp listener.
mTcpListener = new TcpListener(theAddress, port);
Console.WriteLine($"Trying to listen on {theAddress}:{port}");
mTcpListener.Start();
Console.WriteLine("Listening...");
Socket socket = null;
try
{
socket = mTcpListener.AcceptSocket();
}
catch (Exception ex)
{
Console.WriteLine(ex.Message);
return;
}
// wait a little for the socket buffer to fill up
await Task.Delay(20);
int bytesAvailable = socket.Available;
var completeBuffer = new List<byte>();
while (bytesAvailable > 0)
{
byte[] buffer = new byte[bytesAvailable];
int bytesRead = socket.Receive(buffer);
completeBuffer.AddRange(buffer.Take(bytesRead));
bytesAvailable = socket.Available;
}
byte[] receivedBytes = completeBuffer.ToArray();
string receivedString = Encoding.ASCII.GetString(receivedBytes);
... works like a charm. The returned string is
GET /MyService/ HTTP/1.1
User-Agent: Wget/1.17.1 (cygwin)
Accept: */*
Accept-Encoding: identity
Host: 127.0.0.1:45987
Connection: Keep-Alive
So, as a workaround, I could implement my own http request parser and response generator... not that I like being forced to reinvent the wheel.

HTTP POST not working in OWIN Self-Host Web API

I am self self hosting a Web API. Any Get Reqeust I make from my integration tests works fine. However any POST request throws connection refused. I can't seem to get a handle on what is happening.
Error Message
system.Net.HttpRequestException: An error occured while sending the request to the remote server. SocketException: no connection could be made because the target machine actively refused.
Code
using (WebApp.Start<App_Start.TestConfiguration>("http:/localhost:8216"))
{
var client = new HttpClient();
client.BaseAddress = new System.Uri("http://127.0.0.1:8216");
var response = await client.PostAsync("/api/MyController", new StringContent("something"));
}
controller
public string Post(string value)
{
return "Hello!";
}
I've got the same issue and found that it is necessary to use [FromBody] attribute before your method params. In this case it can parse request payload and you can reach your methods
Hope that helps
Could it be you're missing a / on:
using (WebApp.Start<App_Start.TestConfiguration>("http:/localhost:8216"))
it should be http://localhost:8216.

WCF Service - HTTP Request and Response

I have 2 WCF services:
1. Inbound - the client calls this service.
2. Outbound - we send information to client.
We now know that the response from client will be in default http response for outbound, and they want us to send a default http response for inbound.
Right now, I have specified the response object as a class. How do I implement http response?, how can I manage my services to send a http response?.
I have tried to search around but I am not getting any starter links for this.
Could you please guide me in the right direction?
What should my response object look like in this case?
I solved my issue with this:
To set the response object with the value:
WebOperationContext ctx = WebOperationContext.Current;
ctx.OutgoingResponse.StatusCode = System.Net.HttpStatusCode.OK;
To retrieve the value I used this:
int statuscode = HttpContext.Current.Response.StatusCode;
string description = HttpContext.Current.Response.StatusDescription;

Categories