Bug 34715

Summary: HttpClient incorrectly works with multiple headers
Product: [Mono] Class Libraries Reporter: Pavel Martynov <mr.xkurt>
Component: SystemAssignee: Marek Safar <masafa>
Status: RESOLVED FIXED    
Severity: normal CC: masafa, mono-bugs+mono
Priority: ---    
Version: 4.2.0 (C6)   
Target Milestone: Untriaged   
Hardware: PC   
OS: Linux   
Tags: Is this bug a regression?: ---
Last known good build:

Description Pavel Martynov 2015-10-09 09:57:20 UTC
Server response:
$ curl -XGET -I http://test-host:8082/
HTTP/1.1 200 OK
Server: Suave/0.0.0.0 (http://suave.io)
Date: Fri, 09 Oct 2015 13:53:36 GMT
X-Custom-Header: first
X-Custom-Header: second
Content-Type: text/html
Content-Length: 6

As you can see there is two "X-Custom-Header" headers.

Client code:
var client = new System.Net.Http.HttpClient();
var request = new System.Net.Http.HttpRequestMessage(System.Net.Http.HttpMethod.Get, new Uri("http://test-host:8082/"));
var resp = client.SendAsync(request).Result;
foreach (var header in resp.Headers)
	Console.WriteLine("{0}: {1}", header.Key, string.Join(", ", header.Value));

Mono result:
$ mono Test.exe
Server: Suave/0.0.0.0, (http://suave.io)
Date: Fri, 09 Oct 2015 13:37:58 GMT
X-Custom-Header: second

Only one "X-Custom-Header: second"

Bu under .NET 4.0:
X-Custom-Header: first, second
Date: Fri, 09 Oct 2015 12:51:58 GMT
Server: Suave/0.0.0.0, (http://suave.io)

Both X-Custom-Header: first, second


Version: mono-complete 4.2.1.60-0xamarin1
Comment 1 Marek Safar 2015-10-12 11:08:49 UTC
This is actually WebRequest bug

Simple repro

using System;
using System.Threading;
using System.IO;
using NUnit.Framework;
using System.Net;
using System.Collections.Generic;
using System.Net.Http.Headers;

class X
{
	static string port = "8810";

	static HttpListener CreateListener (Action<HttpListenerContext> contextAssert)
	{
		var l = new HttpListener ();
		l.Prefixes.Add (string.Format ("http://+:{0}/", port));
		l.Start ();
		l.BeginGetContext (ar => {
			var ctx = l.EndGetContext (ar);

			try {
				if (contextAssert != null)
					contextAssert (ctx);
			} finally {
				ctx.Response.Close ();
			}
		}, null);

		return l;
	}

	public static void Main ()
	{
		var listener = CreateListener (l => {
			var request = l.Request;
			var response = l.Response;
			response.Headers.Add ("X-Custom-Header", "A");
			response.Headers.Add ("X-Custom-Header", "B");
		});

		try {
			var TestHost = "localhost:" + port;
			var LocalServer = string.Format ("http://{0}/", TestHost);

			HttpWebRequest wr = HttpWebRequest.CreateHttp (LocalServer);
			var resp = wr.GetResponse ();
			var vls = resp.Headers.GetValues ("X-Custom-Header");

			// Print 1 where 2 is expected
			Console.WriteLine (vls.Length);
		} finally {
			listener.Close ();
		}
	}
}
Comment 2 Marek Safar 2016-09-13 14:14:57 UTC
Fixed in master and Mono 4.8