How can I send GET request with sockets? - c#

I want to send GET/POST request with sockets, and I have this code:
Socket socket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
socket.Connect(Url, 80);
byte[] contentLenght = Encoding.ASCII.GetBytes(Data);
string[] masRequestString ={
"GET /"+Data+" HTTP/1.1\r\n" ,
"Host: "+Url+"\r\n",
"User-Agent: "+textBox1.Text+"\r\n",
"Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8\r\n",
"Content-Type: application/x-www-form-urlencoded; charset=UTF-8\r\n",
"Referer: "+textBox2.Text+"\r\n"};
string request = string.Concat(masRequestString);
Byte[] bytesSent = Encoding.ASCII.GetBytes(request);
socket.Send(bytesSent, bytesSent.Length, 0);
Byte[] bytesReceived = new Byte[0x400];
int bytes = socket.Receive(bytesReceived, bytesReceived.Length, 0);
string content = Encoding.ASCII.GetString(bytesReceived, 0, bytes);
When I try to send the request sniffers don't see it. Why?

I have no idea of how you do sniffing but
You are at not sending a correct request, because it misses an \r\n at the end.
You are expecting the server to close the connection after the response is done. Instead you need to care about content-length header and chunked encoding.
And apart from that sending a Content-type header with a GET request makes no sense, because there will be no content sent inside a GET request (only in the response).
I suggest you first get a deeper knowledge of HTTP works before you are trying to implement it. Much better of course would be to use already existing implementations, because HTTP is not the simply protocol it seems to be after having only a short look.

Don't try implement HTTP yourself, socket can take your data and wrap it.
Use HTTP library:
using System.Net;
string url = "https://www.example.com/scriptname.php?var1=hello";
HttpWebRequest request = (HttpWebRequest)WebRequest.Create(url);
HttpWebResponse response = (HttpWebResponse)request.GetResponse();
Stream resStream = response.GetResponseStream();

Related

What sort of message does Snapd's API expect?

Snapd has documentation on a REST API.
I'm able to connect to the socket from C# using the following
var snapSocket = new Socket(AddressFamily.Unix, SocketType.Stream, ProtocolType.IP);
var snapEndpoint = new UnixEndPoint("/run/snapd.socket");
snapSocket.Connect(snapEndpoint);
var req = Encoding.ASCII.GetBytes("GET /v2/system-info HTTP/1.1");
snapSocket.Send(req, req.Length, 0);
var bytesReceived = new byte[256];
var bytes = 0;
var response = "";
do
{
bytes = snapSocket.Receive(bytesReceived, bytesReceived.Length, 0);
response = response + Encoding.ASCII.GetString(bytesReceived, 0, bytes);
} while (bytes > 0);
Console.WriteLine(response);
But everything halts at snapSocket.Receive - a response is never sent. I suspect that there's something wrong with the message that I'm sending it.
It turns out that it expects a standard HTTP request, which means a Host: line, a Connection: Close line, and two \ns at the very end are required.
The documentation's following claim...
While it is expected to allow clients to connect using HTTPS over a TCP socket, at this point only a UNIX socket is supported.
... is meant only to imply that HTTPS and TCP do not work yet - HTTP is currently the valid request format even when using the UNIX Socket.
I am not fluent in C# at all, but maybe this python snippet can help lead into a solution:
import requests_unixsocket
session = requests_unixsocket.Session()
r = session.get('http+unix://%2Frun%2Fsnapd.socket/v2/snaps')
r.raise_for_status()
r.json()

How can I avoid a "Bad Request - Invalid Hostname" error when making a REST call from a Compact Framework client?

I used this code from here to try to call a REST Controller method on a Web API server app from a Compact Framework client:
public static void SendXMLFile3(string uri, string data)
{
WebRequest request = WebRequest.Create (uri);
request.Method = "POST";
string postData = data;
byte[] byteArray = Encoding.UTF8.GetBytes (postData);
request.ContentType = "application/x-www-form-urlencoded";
request.ContentLength = byteArray.Length;
Stream dataStream = request.GetRequestStream ();
dataStream.Write (byteArray, 0, byteArray.Length);
dataStream.Close ();
WebResponse response = request.GetResponse ();
MessageBox.Show(((HttpWebResponse) response).StatusDescription);
dataStream = response.GetResponseStream ();
StreamReader reader = new StreamReader (dataStream);
string responseFromServer = reader.ReadToEnd();
MessageBox.Show(responseFromServer);
reader.Close ();
dataStream.Close ();
response.Close ();
}
...I had earlier tried this code, which I got from the book "Microsoft .NET Compact Framework":
public static void SendXMLFile2(string uri, string data)
{
WebRequest req = WebRequest.Create(uri);
req.Method = "Post";
req.ContentType = "text/plain; charset=utf-8";
byte[] encodedBytes = Encoding.UTF8.GetBytes(data);
req.ContentLength = encodedBytes.Length;
Stream requestStream = req.GetRequestStream();
requestStream.Write(encodedBytes, 0, encodedBytes.Length);
requestStream.Close();
WebResponse result = req.GetResponse();
MessageBox.Show(result.ToString());
}
...but I get "400 - Bad Request" with the new (as well as the old) code.
My initial attempt also does not work, with the same result (400):
public static string SendXMLFile(string xmlFilepath, string uri, int timeout)
{
HttpWebRequest myHttpWebRequest=(HttpWebRequest)WebRequest.Create(uri);
myHttpWebRequest.AllowWriteStreamBuffering=false;
string postData = "<Command><DSD><line_id>1</line_id><invoice_no>david_dsd</invoice_no>. . .</DSD></Command>"; // TODO: if this works, replace it with the real data
myHttpWebRequest.Method="POST";
UTF8Encoding encodedData = new UTF8Encoding();
byte[] byteArray=encodedData.GetBytes(postData);
myHttpWebRequest.ContentType = "application/xml";
myHttpWebRequest.ContentLength=byteArray.Length;
Stream newStream=myHttpWebRequest.GetRequestStream();
newStream.Write(byteArray,0,byteArray.Length);
newStream.Close();
HttpWebResponse myHttpWebResponse=(HttpWebResponse)myHttpWebRequest.GetResponse();
return myHttpWebResponse.StatusDescription;
}
There is much more about the plethora of variations I have tried here, where I have reached my length-of-post limit.
UPDATE
Note that the Server code doesn't know/care that the file is XML:
[HttpPost]
[Route("api/inventory/sendXML/{userId}/{pwd}/{filename}")]
public async Task SendInventoryXML(String userId, String pwd, String fileName)
{
Task task = Request.Content.ReadAsStreamAsync().ContinueWith(t =>
{
var stream = t.Result;
using (FileStream fileStream = File.Create(String.Format(#"C:\HDP\{0}.xml", fileName), (int)stream.Length))
{
byte[] bytesInStream = new byte[stream.Length];
stream.Read(bytesInStream, 0, (int)bytesInStream.Length);
fileStream.Write(bytesInStream, 0, bytesInStream.Length);
}
});
}
UPDATE 2
I tried Charles to see if it would pick up the local HTTP traffic, but it is also deaf to such (like Fiddler, without special ministrations, anyway). This is what Charles looks like after getting the "400 - Bad Request" error:
UPDATE 3
I found this suggestion somewhere to get Fiddler to show local HTTP traffic:
Tools--> Fiddler Options. Choose Connections tab. Check the 'USe PAC Script' option.
...but it didn't work - I still see no HTTP traffic when getting the "400 (Bad Request)" message.
UPDATE 4
I am now seeing "400 (Bad Request)" in Fiddler 2, too; to get it, I enter any of the following in Postman (don't see this in Fiddler when calling from CE/CF/handheld app):
http://SHANNON2:21608/api/inventory/sendXML/su/su/blablee // Hostname
http://SHANNON2.:21608/api/inventory/sendXML/su/su/blablee // Hostname with Fiddler-fooler appended "."
http://192.168.125.50:21608/api/inventory/sendXML/su/su/blablee // IP Address
(Fiddler does not capture anything if I replace the hostname or IP Address with "localhost")
Note: For these URLs in Postman, I have "Post" (as opposed to GET, etc.) selected, and an XML file attached.
Inspectors.Headers in Fiddler shows:
POST /api/inventory/sendXML/su/su/blablee HTTP/1.1
Although I consider this a minor debugging victory, I still don't see why I'm getting the "400" error.
Fiddler tells me, in the Inspectors.WebView pane:
Bad Request - Invalid Hostname
--------------------------------------------------------------------------------
HTTP Error 400. The request hostname is invalid.
How can that be? When I run it from Postman, I hit the breakpoint in the server - if the hostname is invalid, why is it being reached?
UPDATE 5
Testing the call from Fiddler Composer and Postman, the only way I can reach the breakpoint in the server code is by using "localhost" - replacing that with the PC's IPAddress (192.168.125.50) or HostName (SHANNON2) does not reach the breakpoint. While "interesting," calling "localhost" from the handheld device is obviously not an option.
UPDATE 6
Related new question here.
UPDATE 7
The crux of the biscuit was adding at the command prompt either this:
netsh http add urlacl url=http://shannon2:80/ user=everyone
...or this:
netsh http add urlacl url=http://shannon2:8080/ user=everyone
See Update 5 here for more details
Adding my observations, if you are facing the issue Bad Request - Invalid Hostname while calling the API from Postman. Something like this.
Consider adding the Host in Headers, it will work.
Updated after someone is not able to view the image: If the images are not loading, then basically this you have to do:
Basically, you have to add Content-Length and Host. Postman auto calculates when the request is sent. These can be enabled in postman by unhiding auto-generated headers in Postman. or you can set by your own.
The crux of the biscuit was adding at the command prompt either this:
netsh http add urlacl url=http://shannon2:80/ user=everyone
...or this:
netsh http add urlacl url=http://shannon2:8080/ user=everyone
See Update 5 here for more details

how to connect java servlet from c# windows form?

I already have an existing application implemented using java in app engine....now i want to connect this servlet from c# forms program ?,...this is the tried out code for request
HttpWebRequest authRequest = (HttpWebRequest)HttpWebRequest.Create(googleLoginUrl);
byte[] buffer = Encoding.ASCII.GetBytes(postData);
authRequest.ContentLength = buffer.Length;
Stream postDataStr=authRequest.GetRequestStream();
postDataStr.Write(buffer, 0, buffer.Length);
postDataStr.Close();
now it is connected to the GSE(Google Servlet Engine)...i want a response for this....how to implement that?
You just need to read the response:
HttpWebResponse response = (HttpWebResponse)authRequest.GetResponse ();
Console.WriteLine ("Content length is {0}", response.ContentLength);
Console.WriteLine ("Content type is {0}", response.ContentType);
string raw_html = (new StreamReader(response.GetResponseStream()).ReadToEnd();
You can see further examples from: http://msdn.microsoft.com/en-us/library/system.net.httpwebrequest.getresponse.aspx
Note: I believe since you're posting data you'll also have to set your authRequest as a POST via:
authRequest.Method = "POST";

Issue WebRequest while reading NetworkStream of TcpListener

Following on from the post How to create a simple proxy in C#? I have been playing around with implementing a basic proxy.
Where I am getting stuck and confused is trying to issue a WebRequest with the information provided in the original request.
Using the following code.
WebRequest webRequest = WebRequest.Create("http://www.google.com");
(webRequest as HttpWebRequest).UserAgent = "MOZILLA/5.0 (WINDOWS NT 6.1; WOW64) APPLEWEBKIT/537.1 (KHTML, LIKE GECKO) CHROME/21.0.1180.75 SAFARI/537.1";
webRequest.Method = "GET";
WebResponse webResponse = webRequest.GetResponse();
Stream responseStream = webResponse.GetResponseStream();
byte[] responseBytes = responseStream.ReadFully();
I can successfully issue a request and return the page content.
However when I put it inside a Proxy request (IE: TcpListener) like such.
TcpListener _listener = new TcpListener(IPAddress.Any, 1234);
this._listener.Start();
byte[] bytes = new byte[1024];
while (true)
{
TcpClient client = this._listener.AcceptTcpClient();
NetworkStream networkStream = client.GetStream();
int i = networkStream.Read(bytes, 0, bytes.Length);
while (i != 0)
{
string data = System.Text.Encoding.ASCII.GetString(bytes, 0, i);
RequestHeader header = new RequestHeader(data.ToUpper());
WebRequest webRequest = WebRequest.Create(header.URL);
(webRequest as HttpWebRequest).UserAgent = header.UserAgent;
webRequest.Method = "GET";
WebResponse webResponse = webRequest.GetResponse(); //It gets here and never returns
Stream responseStream = webResponse.GetResponseStream();
byte[] responseBytes = responseStream.ReadFully();
networkStream.Write(responseBytes, 0, responseBytes.Length);
i = networkStream.Read(bytes, 0, bytes.Length);
}
client.Close();
}
It blocks at the line WebResponse webResponse = webRequest.GetResponse(); and never returns.
This has definitely got nothing to do with the data provided by the RequestHeader class I created as I've also tried hardcoding the values.
I'm assuming I'm missing something fundamental about the way sockets work in such a scenario and the approach required. Hopefully someone can clarify for me.
Yeah, you are assuming you have read all the header.
Instead of this, some kind of state machine should be implemented to parse the incoming HTTP-request. The state machine must collect the information about the request and, of course, detect the end of request, then you process the request (proxy stuff) and send the response. Just Google C# http state machine for examples.
So it turned out to be a proxy issue.
Basically for testing I needed to set the machine proxy to 127.0.0.1:1234 or similar.
This in turn was being used in the default settings when initializing a WebRequest.
So all I needed to do in the end was the following to bypass the proxy.
(webRequest as HttpWebRequest).UserAgent = header.UserAgent;
webRequest.Method = "GET";
webRequest.Proxy = null; //Adding this line cleared the proxy.

How to read HTTP POST Request Message Parameters in c#

I am able to read the url and entire page but not able to read the HTTP POST Request Message Parameters in c#.
In my situation i am posting a post url to a site after they verify they send me a HTTP Post message with parameters like id.
here is my code in c#
HttpWebRequest request1 = (HttpWebRequest)WebRequest.Create(uri);
postsourcedata = "processing=true&Sal=5000000";
request1.Method = "POST";
request1.ContentType = "application/x-www-form-urlencoded";
request1.ContentLength = postsourcedata.Length;
request1.UserAgent = "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1)";
Stream writeStream1 = request1.GetRequestStream();
UTF8Encoding encoding1 = new UTF8Encoding();
byte[] bytes1 = encoding1.GetBytes(postsourcedata);
writeStream1.Write(bytes1, 0, bytes1.Length);
writeStream1.Close();
HttpWebResponse response = (HttpWebResponse)request.GetResponse();
Stream responseStream = response.GetResponseStream();
StreamReader readStream = new StreamReader(responseStream, Encoding.UTF8);
string page = readStream.ReadToEnd();
//page.Close();
return page.ToString();
They are sending me request parameters like id and text , how to read these parameters on my side.I am posting to the website through a web service.
Can anyone help me with this?
If they are sending you an HTTP Post message that means that you either need to have a web server or something that understands HTTP protocol to handle the requests, correct?
What I mean is that by your description, it looks like they are sending you an HTTP Request to port 80 or port 443 (https) and you should have asp.net page to handle the request. Once they hit that page, you can simply do:
Request.Parameters("Id")
Request.Parameters("Text")
And so on.

Categories

Resources