4

EDIT: Please note, I know the heart of the problem lies in the service I need to communicate with is not following protocol. This is software which I am not capable of touching and will not be changed anytime soon. Thus, I need help with circumventing the problem and breaking protocol. Development at its finest!

I'm attempting to communicate with an external service. Whomever made it decided to split various calls into not just different folders, but also HTTP request types. The problem here, is that I need to send a GET request that includes content.

Yes, this violates the protocol. Yes, this works if I formulate the call using Linux commands. Yes, this works if I manually craft the call in Fiddler (although Fiddler gets angry at the breach of protocol)

When I craft my call, it's wrapped in an async method. Sending it, however, results in an error:

Exception thrown: 'System.Net.ProtocolViolationException' in mscorlib.dll ("Cannot send a content-body with this verb-type.")

Code for the call:

    /// <summary>
    /// Gets a reading from a sensor
    /// </summary>
    /// <param name="query">Data query to set data with</param>
    /// <returns></returns>
    public async Task<string> GetData(string query)
    {
        var result = string.Empty;

        try
        {
            // Send a GET request with a content containing the query. Don't ask, just accept it 
            var msg = new HttpRequestMessage(HttpMethod.Get, _dataApiUrl) { Content = new StringContent(query) };
            var response = await _httpClient.SendAsync(msg).ConfigureAwait(false);

            // Throws exception if baby broke
            response.EnsureSuccessStatusCode();

            // Convert to something slightly less useless
            result = await response.Content.ReadAsStringAsync();
        }
        catch (Exception exc)
        {
            // Something broke ¯\_(ツ)_/¯
            _logger.ErrorException("Something broke in GetData(). Probably a borked connection.", exc);
        }
        return result;
    }

_httpClient is created in the constructor and is a System.Net.Http.HttpClient.

Does anyone have an idea how to override the regular protocols for the HttpClient and force it to make the call as a GET call, but with a content containing my query for the server?

Tank
  • 41
  • 7
  • Can't you add your query in the get URL? – Steven Sep 30 '15 at 09:37
  • Is using plain TCP an option? – Kuba Wyrostek Sep 30 '15 at 09:41
  • Currently, the only option is to send a GET request with the query in the content portion. The headaches working with universities where not everyone agrees and half the stuff is just hacked is going to make this PhD painful, I think. – Tank Sep 30 '15 at 09:47
  • 2
    @Tank, HTTP in plain is just a bunch of bytes sent to and received from server. If you do not use any fancy stuff of HttpClient then simply send your request and receive response using stream readers and writers over TCP connection (which would be totally unaware that it violates HTTP rules ;)) – Kuba Wyrostek Sep 30 '15 at 10:00
  • 1
    I looked at the code used by `HttpClient` and to me it seems pretty hard to avoid its check without having to massively rewrite a lot of code. Can you consider using `WebRequest`? – Matteo Umili Sep 30 '15 at 10:28
  • `Development at its finest!` Deliberately violating one of **the** core specifications of the entire WWW for more than 15 years without good reason? Sounds more like "Development at its worst!" to me... – Stephen Cleary Sep 30 '15 at 11:07
  • When does development, especially tied to research, one to worry about trifling details like standards? *facedesk* @codroipo I was looking at it too and I'm coming to the same conclusion. Damned protocol-adhering libraries! I was hoping I wouldn't have to use multiple libraries really, keep my code clean, but eh, guess it's time to add comments shifting the blame elsewhere ;) – Tank Sep 30 '15 at 12:36
  • @Tank I'm checking `HttpWebRequest` and it seems pretty hard even here to avoid the verb check – Matteo Umili Sep 30 '15 at 14:10
  • Having the same issue, it gives an error the moment I attempt to stream my content to it. There's gotta be a way, no way I'm incorporating working java code into this. – Tank Sep 30 '15 at 18:05
  • You can try sending JWEs to your query string. It just might work for your case.. – kerafill Oct 02 '15 at 10:51

1 Answers1

1

To me the less devastating way to achieve that is to set ContentBodyNotAllowed field of Get KnownHttpVerb to false using reflection. You can try with this:

public async Task<string> GetData(string query)
{
    var result = string.Empty;
    try
    {
        var KnownHttpVerbType = typeof(System.Net.AuthenticationManager).Assembly.GetTypes().Where(t => t.Name == "KnownHttpVerb").First();
        var getVerb = KnownHttpVerbType.GetField("Get", BindingFlags.NonPublic | BindingFlags.Static);
        var ContentBodyNotAllowedField = KnownHttpVerbType.GetField("ContentBodyNotAllowed", BindingFlags.NonPublic | BindingFlags.Instance);
        ContentBodyNotAllowedField.SetValue(getVerb.GetValue(null), false);

        var msg = new HttpRequestMessage(HttpMethod.Get, _dataApiUrl) { Content = new StringContent(query) };
        var response = await _httpClient.SendAsync(msg).ConfigureAwait(false);
        response.EnsureSuccessStatusCode();

        result = await response.Content.ReadAsStringAsync();
    }
    catch (Exception exc)
    {
        _logger.ErrorException("Something broke in GetData(). Probably a borked connection.", exc);
    }
    return result;
}
Matteo Umili
  • 3,412
  • 1
  • 19
  • 31