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

B. Clay Shannon picture B. Clay Shannon · Sep 8, 2014 · Viewed 9.5k times · Source

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:

enter image description here

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

Answer

KushalSeth picture KushalSeth · Mar 9, 2021

Adding my observations, if you are facing the issue Bad Request - Invalid Hostname while calling the API from Postman. Something like this.

enter image description here

Consider adding the Host in Headers, it will work.

enter image description here