HttpWebRequest not sending cookies on POST - vb.net

I’m writing a http module to work as a reverse proxy, i.e. receives a request from a browser, sends it on to the target site, receives a response and sends that back to the browser.
Its all working fine, except for a problem with forwarding cookies from the browser request to the target site on a Post. All headers and form data are correct on the outgoing request, but no cookies are included.
I’ve run fiddler on both the request from the browser to IIS and the outgoing httpwebrequest and proven this to be the case. Running the module in debug shows that the cookies are found in the request from the browser and successfully placed in the cookiecontainer of the httpwebrequest, but they just don’t appear in the actual request sent out.
If I hack (in debug) the outgoing request method to a Get, then they go, but they don’t go for a Post.
I’ve also tracked the request/response from a browser direct to the target site using Fiddler, and the request seems identical in all three cases (browser to target, browser to my IIS module, IIS module to target), except that the IIS module to target omits the cookies.
Here’s the code (VB.Net, and tried in 2.0 and 4.5):
' set up the request to the target
Dim reqTarget As System.Net.HttpWebRequest
reqTarget = CType(System.Net.HttpWebRequest.Create(strTargetURL & strTargetPath & qstring), System.Net.HttpWebRequest)
' copy relevant info, cookies etc from the application request to the target request
CopyAppRequest(application.Context.Request, reqTarget)
' send the request and get the response
Dim rspTarget As System.Net.HttpWebResponse = CType(reqTarget.GetResponse(), System.Net.HttpWebResponse)
Private Sub CopyAppRequest(ByRef reqApp As System.Web.HttpRequest, ByRef reqTarget As System.Net.HttpWebRequest)
' copy over the headers
For Each key As String In reqApp.Headers.AllKeys
Select Case key
Case "Host", "Connection", "Content-Length", "Accept-Encoding", "Expect", "Authorization", "If-Modified-Since"
' not sure if we need to process these
Case "Connection"
reqTarget.Connection = reqApp.Headers(key)
Case "Content-Type"
reqTarget.ContentType = reqApp.Headers(key)
Case "Accept"
reqTarget.Accept = reqApp.Headers(key)
Case "Referer"
reqTarget.Referer = reqApp.Headers(key)
Case "User-Agent"
reqTarget.UserAgent = reqApp.Headers(key)
Case "Cookie"
' do nothing, cookies are handled below..
Case Else
reqTarget.Headers.Add(key, reqApp.Headers(key)
End Select
Next
reqTarget.Method = reqApp.HttpMethod
reqTarget.AllowAutoRedirect = False
If reqTarget.Method = "POST" Then
reqTarget.ContentLength = reqApp.ContentLength
Dim datastream() As Byte = System.Text.Encoding.UTF8.GetBytes(reqApp.Form.ToString)
reqTarget.ContentLength = datastream.Length
Dim requestwriter As System.IO.Stream = reqTarget.GetRequestStream
requestwriter.Write(datastream, 0, datastream.Length)
requestwriter.Close()
requestwriter.Dispose()
End If
Dim CookieJar As New System.Net.CookieContainer
reqTarget.CookieContainer = CookieJar
For Each key As String In reqApp.Cookies.AllKeys
Dim tgtCookie As New System.Net.Cookie
With tgtCookie
.Name = reqApp.Cookies.Item(key).Name
.Value = reqApp.Cookies.Item(key).Value
.Domain = ".domain.com"
.Path = "/"
.Expires = DateAdd(DateInterval.Month, 1, System.DateTime.Now)
.HttpOnly = True
End With
CookieJar.Add(tgtCookie)
Next
End Sub
Note: the domain I’m trying to reach is in the form abc.domain.com (i.e. it’s a subdomain, and no www), the reason I’ve tried the .domain.com form is that is the form used in the cookies that are received in the response. I’ve also tried other combinations such as abc.domain.com, .abc.domain.com, etc. Also I’ve tried creating a Uri object and using that method to add the cookie into the cookiecontainer.
I’ve tried everything I can think of and can find on forums…. Anyone got any suggestions? I suspect I’ve missed something obvious!
Of course, any other comments on how the code above can be improved will be appreciated.
Thanks.

Ok, I found the issue...
I was using Fiddler to see what was going on with http, and Fiddler was correct. However, when I used Wireshark, I found that the http request was being sent earlier than I thought, and only on the Post.
It turned out that the requestwriter.write line caused the http request to be sent, not the GetResponse (as is the case with Get). So, anything I changed in the httpwebrequest after the requestwriter.write didn't get sent.
The fix - I just moved all the header and cookie set up above the requestwriter.write and it all worked.
How frustrating, but at least its fixed now :)
If anyone has any feedback on whether I've got something wrong that's causing this to happen, please let me know.

Related

Problem with Open method of MSXML2.ServerXMLHTTP.6.0 PATCH request

I have been using MSXML2.XMLHTTP.6.0 successfully with my Excel VBA script for a couple years, for both GET and POST requests. The POST request looks like:
Dim zipService as Object
Dim Query As String
Dim Body As String
Set zipService = CreateObject("MSXML2.XMLHTTP.6.0")
Query = "https://10.xxx.xxx.xxx:443/api/rest/v1/bulk/thresholdRules/"
zipService.Open "POST", Query, False
zipService.setRequestHeader "Authorization", "Basic " & gsUserIDPW
zipService.setRequestHeader "Content-Type", "application/json"
zipService.setRequestHeader "Accept", "application/xml"
Body = "Body of the request"
zipService.send (sBody)
Now I need to need to make a PATCH request to a new REST call for the same API. I have tested the PATCH REST call in Postman, and it works successfully. Using PUT in Postman also works. However, in Excel, when I try to do the Open call using PATCH (or PUT), the Open call fails with a -2147012891 error.
Any suggestions? Are PATCH and PUT allowed with the Open method? Are there other parameters I have to specify? All the code examples I find online are always GET and POST requests.

404 error while getting server response vb.net

I'm a totally beginner with webrequest, so I have no idea about what cause the error I get.
I try to login on a form following the microsoft tutorial for webrequest, but when I want to get the server response, I have the following error :
"the remote server returned an error (404) not found"
So I know that the URL I use actually exist and then wonder which part of the code is bad. Maybe it's because I'm doing an HTTPS request unlike the tutorial and it changes something ?
Also, I'm a little confused by getting directly the answer from the server : shouldn't there be kind of a trigger to know when the server answered ?
Dim request = WebRequest.Create("https://ssl.vocabell.com/mytica2/login")
request.Credentials = CredentialCache.DefaultCredentials
request.Method = "POST"
Dim byteArray = Encoding.UTF8.GetBytes("_username=x&_password=x")
request.ContentType = "application/x-www-form-urlencoded"
request.ContentLength = byteArray.Length
Dim dataStream = request.GetRequestStream()
dataStream.Write(byteArray, 0, byteArray.Length)
dataStream.Close()
Dim reponse = request.GetResponse() 'ERROR
MsgBox(CType(reponse, HttpWebResponse).StatusDescription)
Using ds = reponse.GetResponseStream
Dim reader = New StreamReader(ds)
MsgBox(reader.ReadToEnd)
End Using
reponse.Close()
Thank you for your time, and if you have any relevant tutorial on the topic I would be glad to read it !
The page you've mentioned does exist and uses HTTPS, but if you look at the form tag within it, it's like this:
<form class="login-form form-horizontal" action="/mytica2/login_check" method="POST">
This means it doesn't post the form back to the same URL as the page, instead it sends it to the URL contained within that "action" attribute. If you're trying to use your code to simulate the submission of the login form then it looks like you need to send your POST request to https://ssl.vocabell.com/mytica2/login_check instead.

HTTP GET with my API

I have a current web site that captures data send via querystring
I would like to repost this data to a different API using HTTP GET and capture the response from that site. Response.Redirect works but can not read the results of that post.
This sample code should get you started. It requests the page from a url with querystring values passed, and stores the response in a variable then response.write's the contents.
Set objXML = Server.CreateObject("MSXML2.ServerXMLHTTP")
objXML.Open "GET", "http://www.test.com/test.asp?var1=val1", false
objXML.Send ""
strResponse = objXML.ResponseText
Response.Write strResponse

500 error on api request. works fine when called through browser

Hello I have an api which authenticates the user login . Now when I hit this rest service in my browser it displays the result but when I try to do this using my code it gives in 500 error. Please help me with this .
My Api: http://abhinavevent2014.sched.org/api/auth/login?api_key=1309658400d57c8cfc6081f8361de52c&username=abhinavm#test.com&password=test
string url = #"http://abhinavevent2014.sched.org/api/auth/login?api_key=1309658400d57c8cfc6081f8361de52c&username=abhinavm#test.com&password=test";
Encoding encode = System.Text.Encoding.GetEncoding("utf-8");
WebRequest requestfriend = WebRequest.Create(url);
WebResponse responsefriend = requestfriend.GetResponse(); ( This is where it blows)
Stream streamResponse = responsefriend.GetResponseStream();
StreamReader streamReaderResponse = new StreamReader(streamResponse, encode);
jsonResult = streamReaderResponse.ReadToEnd();
return jsonResult.ToString();
You need to use User-Agent in the headers, as the documentation says:
You must also send requests with a User-Agent in the headers, as Sched
filters out requests with no User-Agent.
Sched API Doc
Browser automatically does that, so it can retrieve the data.

No response after authentication success in pentaho?

I try to use Basic Authentication to make a login into Pentaho by using .NET code
My code is:
Dim request = WebRequest.Create("http://x.x.x.x:8080/pentaho/Home")
Dim authInfo As String = Convert.ToString(userName) & ":" & Convert.ToString(userPassword)
authInfo = Convert.ToBase64String(Encoding.[Default].GetBytes(authInfo))
request.Headers("Authorization") = "Basic " & authInfo
Dim response As WebResponse = request.GetResponse()
You can see that I pass the authorization header with Basic username:password with Base64 encode.
for the last line of above code
Dim response As WebResponse = request.GetResponse()
you can see that I get the response from pentaho server then assign to variable response
In running, I found that Pentaho can return response and put the value to variable response.It seem okay that the authentication is passed and I login successfully
but when I input a link http://x.x.x.x:8080/pentaho/Home the login page still prompt and I need to login again....
Do you know what code I missing so that the Pentaho cannot login auto after above code?
Thanks you much!!!!!
Have you tried putting it as parameters in the url i.e :
?userid=joe&password=password
However, looking at it again it seems if you're successfully getting a logged in response, then the next request you are not logged in then you have not preserved the session/cookie between those two requests. Easily done in java with httpclient, not so sure about .net