405 - Method Not Allowed HttpWebRequest - vb.net

I have a problem when trying to send a POST request. The sending method looks like this:
Public Sub SendXML(ByVal file As String)
Dim reader As New StreamReader(file)
Dim data As String = reader.ReadToEnd()
reader.Close()
Dim request As HttpWebRequest = WebRequest.Create("http://blah/Request")
request.Method = "POST"
System.Net.ServicePointManager.Expect100Continue = False
Dim bytes As Byte() = System.Text.Encoding.ASCII.GetBytes(data)
request.ContentLength = bytes.Length
Dim oStreamOut As Stream = request.GetRequestStream()
oStreamOut.Write(bytes, 0, bytes.Length)
oStreamOut.Close()
Dim response As HttpWebResponse = request.GetResponse()
End Sub
When running this I get the above error. Through Fiddler I can see that the request looks like:
POST http://blah/Request HTTP/1.1
Host: blah
Content-Length: 322
Proxy-Connection: Keep-Alive
<?xml version="1.0"?>
<Envelope>
<Header>
<UserID>uid</UserID>
<Password>pass</Password>
<SessionID />
<RequestType>GetDetails</RequestType>
<POSCompany>01</POSCompany>
<PackageType>DATA</PackageType>
<ActionType>READ</ActionType>
<SnoopUserID />
</Header>
<Body>
<MagicNumber>124</MagicNumber>
</Body>
</Envelope>
Now looking at this I suspected that it was due to the fact that the server does not accept POST messages. But some other reading suggests that the the URI http://blah/Request has been generated with a proxy and should be /Request so the line should read POST /Request HTTP/1.1
So what would be the common reason for this? And if it is a proxy problem, how is it sorted?
As asked below, I have created a new question for the more specific request. Changing absolute URI to relative in HTTP POST header

There is nothing wrong with the POST request, so the problem must lie elsewhere.
There are a number of other places along the way that could be causing trouble:
There could be a bad proxy between you and the server that is changing the HTTP method
The server could be malfunctioning or simply no support POST
My guess, however, is that the server is doing more than just looking at the HTTP method and is instead giving you a 405 error in response to the RPC call that your XML payload is wrapping.
Some RPC servers will (erroneously) use HTTP status codes like this to indicate that the requested method cannot be executed, or that something else is wrong with the request that is of a permissions and security nature.
If the server is slightly better behaved (and you are lucky), it should be returning additional information in the response body that might indicate where the 405 error is coming from.

Are you missing the Content-Type header required for a POST ?
Read here for details.
I assume it is mandatory.

Your POST appears to be completely invalid. POST data is supposed to be encoded (ie, as multipart/form-data) and use correct content-type (ie, application/x-www-form-urlencoded) with proper encoding and boundaries etc. You are just sending the server a lump of text and I'm not surprised it flips out.
I'm not 100% sure what VB is doing behind the scenes but this MSDN page suggests you need to set the content-type to a supported method and you probably need Content-Disposition: form-data in your headers as well. I found an example that does this and adds the MIME boundaries:
string FileData = "this is test file data\r\n"; // test data to send.
StringBuilder DataString = new StringBuilder();
DataString.Append(dataBoundary + "\r\n");
//This sends the viewstate info
DataString.Append("Content-Disposition: form-data; name=" + HiddenValue
+ "\r\n"
+ dataBoundary + "\r\n");
DataString.Append("Content-Disposition: form-data; name=" + "\"" +
"File1" +
"\"" +
"; filename=" + "\"" + "TestFile3.txt" + "\"" + "\r\n");
DataString.Append("Content-Type: text/plain\r\n\r\n");
DataString.Append(FileData);
DataString.Append(dataBoundary + "\r\n");
DataString.Append("Content-Disposition: form-data; name=" + "\"" +
"Submit1" +
"\"" + "\r\n\r\n" + "Upload\r\n" + dataBoundary + "--\r\n");
That example emulates a file field upload.
For a simpler version you can use request.ContentType = "application/x-www-form-urlencoded" with URL-encoded data like: Dim postData As String = "myURL=http%3A%2F%2Fexample.com%2Findex.php". Note that the format is key=value and the data must be URL-encoded first.
I'm not sure what exactly you need though because a lot depends on what the remote server actually expects for the form and field names. It also depends wether the server is actually following the relevant HTML standards and RFCs. Do you have a working HTML form to use as a guide for what the server expects?

Related

How to corectly set the ContentType property in HttpWebRequest (or how to fix the missing Content-Type header)

I thought I'd share something that took me some time to figure out:
I wrote a simple Post method using HttpWebRequest class.
In HttpWebRequest you can't use HttpWebRequest.Headers collection to set your desired headers when there is a dedicated property for it - you must use that dedicated property. ContentType is one of them. So I created my HttpWebRequest like this:
HttpWebRequest httpWebRequest = (HttpWebRequest)webRequest;
httpWebRequest.Method = "POST";
httpWebRequest.KeepAlive = false;
httpWebRequest.ServicePoint.Expect100Continue = false;
httpWebRequest.ContentType = "application/json";
somewhere below I set the body of my request like this:
using (StreamWriter streamWriter = new StreamWriter(streamWebRequest))
{
streamWriter.Write(sJson);
}
and posted the request using:
WebResponse webResponse = httpWebRequest.GetResponse();
But I kept getting a "400 - Bad Request" error, while the same request worked from Postman. After analyzing the request with Fiddler I found that when I send the request from my app, the Content-Type: application/json header is missing. All the other headers were present, except for Content-Type. I thought I'm setting it wrong, so I googled but didn't find a good answer. After much experimentation I found, that if I move the line:
httpWebRequest.ContentType = "application/json"
after this block:
using (StreamWriter streamWriter = new StreamWriter(streamWebRequest))
{
streamWriter.Write(sJson);
}
then the httpWebRequest.ContentType = "application/json" header finally appears in the request. So, for HttpWebRequest make sure you always set your HttpWebRequest's body/content first, before you set the ContentType property.
Hope it helps
My question above already has the answer, but to mark it as "Answered" I had to add this comment:
Make sure you always set your HttpWebRequest's body/content first, before you set the ContentType property.This way the "Content-Type" header will appear in the request.

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.

Adding Header to Web Request throws an error

When attempting to add a value to the header of an HTTP request, I get the following error:
Specified value does not have a ':' separator. Parameter name: header
To add the header I am using the following code:
Dim request As HttpWebRequest = WebRequest.Create(url)
Dim soapXML As New XmlDocument()
soapXML.LoadXml(soapEnvelope)
request.Headers.Add("SOAPAction", action)
request.Method = "POST"
request.ContentType = "text/xml;charset=""utf-8"""
request.Accept = "text/xml"
Using stream As Stream = request.GetRequestStream()
soapXML.Save(stream)
End Using
I have been looking all over the place and haven't found anybody who has had any similar errors, outside of this SO question: using httpRequest headers?
Which didn't help much.
Does anybody know what I might be doing wrong here?
EDIT 1: Added all the code that I currently have that creates my web request.

eBay API: findItemsAdvanced returning "internal server error" with errorcode "500"

I'm trying to send a findItemsAdvanced request to the eBay API from VB 2012 .NET - however each time I get an "internal server error" with errorcode "500" upon request.GetResponse() where request = System.Net.WebRequest.Create("http://svcs.ebay.com/services/search/FindingService/v1"). I do the request via POST and in XML format with the lines
Dim Xml_bytes() As Byte = System.Text.Encoding.UTF8.GetBytes(xmlstr)
request = System.Net.WebRequest.Create("http://svcs.ebay.com/services/search/FindingService/v1")
'... code setting HEADERS, see below
request.Method = "POST"
request.ContentLength = Xml_bytes.Length
request.ContentType = "text/xml"
Dim requestStream As System.IO.Stream = request.GetRequestStream()
requestStream.Write(Xml_bytes, 0, Xml_bytes.Length)
requestStream.Close()
The code setting the headers I left out, instead here the actual finished headers I supply:
X-EBAY-SOA-SERVICE-NAME: FindingService
X-EBAY-SOA-OPERATION-NAME: findItemsAdvanced
X-EBAY-SOA-SERVICE-VERSION: 1.0.0
X-EBAY-SOA-GLOBAL-ID: EBAY-DE
X-EBAY-SOA-SECURITY-APPNAME: ****
X-EBAY-SOA-REQUEST-DATA-FORMAT: XML
Content-Type: text/xml
And finally the actual XML code which is supplied (through xmlstr var above):
<?xml version='1.0' encoding='utf-8'?>
<findItemsAdancedRequest xmlns='http://www.ebay.com/marketplace/search/v1/services'>
<keywords>caddy</keywords>
<categoryId>77994</categoryId>
<Version>779</Version>
<paginationInput><entriesPerPage>10</entriesPerPage>
</paginationInput>
</findItemsAdvancedRequest>
My main problem is: it does work perfectly with findItemsByKeywords! With the exact same code, only changing the find method and leaving out the <categoryId>77994</categoryId>.
What I tried to do:
different sites (US, german,..)
different categories and keywords.
live AND sandbox APIs with the correct appIDs
including or excluding X-EBAY-SOA-RESPONSE-DATA-FORMAT and/or
X-EBAY-SOA-REQUEST-DATA-FORMAT from the header
It's always the same: it works fine with findItemsByKeyword but I get the "internal server error" with findItemsAdvanced
I have run out of ideas - any suggestions?
Thanks!

Changing absolute URI to relative in HTTP POST header

I have the following POST request:
POST http://blah/Request HTTP/1.1
Host: blah
Content-Length: 322
Proxy-Connection: Keep-Alive
<?xml version="1.0"?>
<Envelope>
<Header>
<UserID>uid</UserID>
<Password>pass</Password>
<SessionID />
<RequestType>GetDetails</RequestType>
<POSCompany>01</POSCompany>
<PackageType>DATA</PackageType>
<ActionType>READ</ActionType>
<SnoopUserID />
</Header>
<Body>
<MagicNumber>124</MagicNumber>
</Body>
</Envelope>
This is failing with the error - (405) Method not supported
An example XML which apparently works on the server is the same but the header has the line POST /Request HTTP/1.1 instead of POST http://blah/Request HTTP/1.1.
I don't know if this is the problem but I am trying to eliminate all possibilites. However, I cannot get the POST request URI to be relative and not absolute. Is there a wat to do this?
The following is the code used for sending the XML.
Public Sub SendXML(ByVal file As String)
Dim reader As New StreamReader(file)
Dim data As String = reader.ReadToEnd()
reader.Close()
Dim request As HttpWebRequest = WebRequest.Create("http://blah/Request")
request.Method = "POST"
System.Net.ServicePointManager.Expect100Continue = False
Dim bytes As Byte() = System.Text.Encoding.ASCII.GetBytes(data)
request.ContentLength = bytes.Length
Dim oStreamOut As Stream = request.GetRequestStream()
oStreamOut.Write(bytes, 0, bytes.Length)
oStreamOut.Close()
Dim response As HttpWebResponse = request.GetResponse()
End Sub
Asked here in response to a request at 405 - Method Not Allowed HttpWebRequest
Following HTTP Error 405 Method not allowed
405 errors often arise with the POST method. You may be trying to
introduce some kind of input form on the Web site, but not all ISPs
allow the POST method necessary to process the form.
All 405 errors can be traced to configuration of the Web server and
security governing access to the content of the Web site, so should
easily be explained by your ISP.