Skip to content

Commit 0fa2da3

Browse files
committed
Discovered a bug with KeepAlives
I am hosting in IIS using owin.host.systemweb I have a single client repeatedly GETing and POSTing some resources I get the error "The server committed a protocol violation. Section=ResponseStatusLine" eventually Here is a small test app to demonstrate it. A WebApp which just hosts a single resource, and a Console app which continually GETs and POSTs to the the WebApp. After running this, an error is shown very quickly
1 parent 718d232 commit 0fa2da3

File tree

12 files changed

+558
-7
lines changed

12 files changed

+558
-7
lines changed

OpenRasta.sln

Lines changed: 19 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -37,15 +37,19 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "OpenRasta.DI.Windsor.Tests.
3737
EndProject
3838
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "OpenRasta.Hosting.AspNet.Tests.Integration", "src\OpenRasta.Hosting.AspNet.Tests.Integration\OpenRasta.Hosting.AspNet.Tests.Integration.csproj", "{088478E0-A0CB-40E1-88C6-A89B50330C6B}"
3939
EndProject
40-
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "OpenRasta.Plugins.Hydra", "src\OpenRasta.Plugins.Hydra\OpenRasta.Plugins.Hydra.csproj", "{05AD6BA1-C771-41DC-94B5-5D4CA2C8DB2F}"
40+
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "OpenRasta.Plugins.Hydra", "src\OpenRasta.Plugins.Hydra\OpenRasta.Plugins.Hydra.csproj", "{05AD6BA1-C771-41DC-94B5-5D4CA2C8DB2F}"
4141
EndProject
4242
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Benchmarks", "Benchmarks", "{F29C9EB9-4B9A-4D8D-A776-6A849CA73DA6}"
4343
EndProject
44-
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "OpenRastaDemo", "src\OpenRasta.Benchmarks\OpenRastaDemo\OpenRastaDemo.csproj", "{B262A705-C1B2-4C1A-AE34-3B15119F609E}"
44+
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "OpenRastaDemo", "src\OpenRasta.Benchmarks\OpenRastaDemo\OpenRastaDemo.csproj", "{B262A705-C1B2-4C1A-AE34-3B15119F609E}"
4545
EndProject
46-
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "OpenRastaDemo.Benchmark", "src\OpenRasta.Benchmarks\OpenRastaDemo.Benchmark\OpenRastaDemo.Benchmark.csproj", "{D5566579-4803-4CF6-AC60-25D7EC075F6C}"
46+
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "OpenRastaDemo.Benchmark", "src\OpenRasta.Benchmarks\OpenRastaDemo.Benchmark\OpenRastaDemo.Benchmark.csproj", "{D5566579-4803-4CF6-AC60-25D7EC075F6C}"
4747
EndProject
48-
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "OpenRastaDemo.Shared", "src\OpenRasta.Benchmarks\OpenRastaDemo.Shared\OpenRastaDemo.Shared.csproj", "{D0389498-4624-4D02-93C5-69F02E678273}"
48+
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "OpenRastaDemo.Shared", "src\OpenRasta.Benchmarks\OpenRastaDemo.Shared\OpenRastaDemo.Shared.csproj", "{D0389498-4624-4D02-93C5-69F02E678273}"
49+
EndProject
50+
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "TestingKeepAlive.Web", "src\TestingKeepAlive.Web\TestingKeepAlive.Web.csproj", "{24B7B587-F7E7-4F56-BEA3-88F1A87C648C}"
51+
EndProject
52+
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "TestingKeepAlive.Console", "src\TestingKeepAlive.Console\TestingKeepAlive.Console.csproj", "{81426C52-CD04-4C22-85E7-F4FF4FB4E865}"
4953
EndProject
5054
Global
5155
GlobalSection(SolutionConfigurationPlatforms) = preSolution
@@ -121,16 +125,24 @@ Global
121125
{D0389498-4624-4D02-93C5-69F02E678273}.Debug|Any CPU.Build.0 = Debug|Any CPU
122126
{D0389498-4624-4D02-93C5-69F02E678273}.Release|Any CPU.ActiveCfg = Release|Any CPU
123127
{D0389498-4624-4D02-93C5-69F02E678273}.Release|Any CPU.Build.0 = Release|Any CPU
128+
{24B7B587-F7E7-4F56-BEA3-88F1A87C648C}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
129+
{24B7B587-F7E7-4F56-BEA3-88F1A87C648C}.Debug|Any CPU.Build.0 = Debug|Any CPU
130+
{24B7B587-F7E7-4F56-BEA3-88F1A87C648C}.Release|Any CPU.ActiveCfg = Release|Any CPU
131+
{24B7B587-F7E7-4F56-BEA3-88F1A87C648C}.Release|Any CPU.Build.0 = Release|Any CPU
132+
{81426C52-CD04-4C22-85E7-F4FF4FB4E865}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
133+
{81426C52-CD04-4C22-85E7-F4FF4FB4E865}.Debug|Any CPU.Build.0 = Debug|Any CPU
134+
{81426C52-CD04-4C22-85E7-F4FF4FB4E865}.Release|Any CPU.ActiveCfg = Release|Any CPU
135+
{81426C52-CD04-4C22-85E7-F4FF4FB4E865}.Release|Any CPU.Build.0 = Release|Any CPU
124136
EndGlobalSection
125137
GlobalSection(SolutionProperties) = preSolution
126138
HideSolutionNode = FALSE
127139
EndGlobalSection
128-
GlobalSection(ExtensibilityGlobals) = postSolution
129-
SolutionGuid = {E66BC41B-A020-4673-8A3F-1986A41479AD}
130-
EndGlobalSection
131140
GlobalSection(NestedProjects) = preSolution
132141
{B262A705-C1B2-4C1A-AE34-3B15119F609E} = {F29C9EB9-4B9A-4D8D-A776-6A849CA73DA6}
133142
{D5566579-4803-4CF6-AC60-25D7EC075F6C} = {F29C9EB9-4B9A-4D8D-A776-6A849CA73DA6}
134143
{D0389498-4624-4D02-93C5-69F02E678273} = {F29C9EB9-4B9A-4D8D-A776-6A849CA73DA6}
135144
EndGlobalSection
145+
GlobalSection(ExtensibilityGlobals) = postSolution
146+
SolutionGuid = {E66BC41B-A020-4673-8A3F-1986A41479AD}
147+
EndGlobalSection
136148
EndGlobal
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
<?xml version="1.0" encoding="utf-8" ?>
2+
<configuration>
3+
<startup>
4+
<supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.6.1" />
5+
</startup>
6+
</configuration>
Lines changed: 120 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,120 @@
1+
using System;
2+
using System.Text;
3+
using System.IO;
4+
using System.Net;
5+
using System.Threading;
6+
7+
namespace TestingKeepAlive.Console
8+
{
9+
10+
class Program
11+
{
12+
static void Main(string[] args)
13+
{
14+
var address = new Uri("http://localhost:52995/");
15+
16+
var writer = TextWriter.Synchronized(System.Console.Out);
17+
18+
var posts = new Thread(() =>
19+
{
20+
var iteration = 0;
21+
while (true)
22+
{
23+
try
24+
{
25+
var request = CreateRequest(address);
26+
request.Method = "POST";
27+
request.ContentType = "application/json";
28+
29+
using (var str = request.GetRequestStream())
30+
{
31+
var bytes = Encoding.UTF8.GetBytes(@"{ ""Data"": [1, 2, 3] }");
32+
str.Write(bytes, 0, bytes.Length);
33+
}
34+
35+
using (var response = (HttpWebResponse)request.GetResponse())
36+
{
37+
writer.WriteLine("{0} {1}", ++iteration, response.StatusCode);
38+
}
39+
}
40+
catch (WebException webException)
41+
{
42+
var stream = webException.Response?.GetResponseStream();
43+
if (stream != null)
44+
{
45+
using (var reader = new StreamReader(stream))
46+
{
47+
writer.WriteLine(reader.ReadToEnd());
48+
}
49+
}
50+
51+
throw;
52+
}
53+
catch (Exception exception)
54+
{
55+
writer.WriteLine(exception);
56+
throw;
57+
}
58+
59+
Thread.Sleep(10);
60+
}
61+
});
62+
63+
var gets = new Thread(() =>
64+
{
65+
var iteration = 0;
66+
while (true)
67+
{
68+
try
69+
{
70+
var request = CreateRequest(address);
71+
request.Method = "GET";
72+
73+
using (var response = (HttpWebResponse)request.GetResponse())
74+
{
75+
writer.WriteLine("{0} {1}", ++iteration, response.StatusCode);
76+
}
77+
}
78+
catch (WebException webException)
79+
{
80+
var stream = webException.Response?.GetResponseStream();
81+
if (stream != null)
82+
{
83+
using (var reader = new StreamReader(stream))
84+
{
85+
writer.WriteLine(reader.ReadToEnd());
86+
}
87+
}
88+
89+
throw;
90+
}
91+
catch (Exception exception)
92+
{
93+
writer.WriteLine(exception);
94+
throw;
95+
}
96+
97+
Thread.Sleep(10);
98+
}
99+
100+
});
101+
102+
posts.Start();
103+
gets.Start();
104+
105+
posts.Join();
106+
gets.Join();
107+
}
108+
109+
static HttpWebRequest CreateRequest(Uri uri)
110+
{
111+
var r = WebRequest.CreateHttp(uri);
112+
113+
// Uncomment either of the following lines and the issue goes away
114+
//r.KeepAlive = false;
115+
//r.ProtocolVersion = HttpVersion.Version10;
116+
117+
return r;
118+
}
119+
}
120+
}
Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
using System.Reflection;
2+
using System.Runtime.CompilerServices;
3+
using System.Runtime.InteropServices;
4+
5+
// General Information about an assembly is controlled through the following
6+
// set of attributes. Change these attribute values to modify the information
7+
// associated with an assembly.
8+
[assembly: AssemblyTitle("TestingKeepAlive.Console")]
9+
[assembly: AssemblyDescription("")]
10+
[assembly: AssemblyConfiguration("")]
11+
[assembly: AssemblyCompany("")]
12+
[assembly: AssemblyProduct("TestingKeepAlive.Console")]
13+
[assembly: AssemblyCopyright("Copyright © 2019")]
14+
[assembly: AssemblyTrademark("")]
15+
[assembly: AssemblyCulture("")]
16+
17+
// Setting ComVisible to false makes the types in this assembly not visible
18+
// to COM components. If you need to access a type in this assembly from
19+
// COM, set the ComVisible attribute to true on that type.
20+
[assembly: ComVisible(false)]
21+
22+
// The following GUID is for the ID of the typelib if this project is exposed to COM
23+
[assembly: Guid("81426c52-cd04-4c22-85e7-f4ff4fb4e865")]
24+
25+
// Version information for an assembly consists of the following four values:
26+
//
27+
// Major Version
28+
// Minor Version
29+
// Build Number
30+
// Revision
31+
//
32+
// You can specify all the values or you can default the Build and Revision Numbers
33+
// by using the '*' as shown below:
34+
// [assembly: AssemblyVersion("1.0.*")]
35+
[assembly: AssemblyVersion("1.0.0.0")]
36+
[assembly: AssemblyFileVersion("1.0.0.0")]
Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,53 @@
1+
<?xml version="1.0" encoding="utf-8"?>
2+
<Project ToolsVersion="15.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
3+
<Import Project="$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props" Condition="Exists('$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props')" />
4+
<PropertyGroup>
5+
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
6+
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
7+
<ProjectGuid>{81426C52-CD04-4C22-85E7-F4FF4FB4E865}</ProjectGuid>
8+
<OutputType>Exe</OutputType>
9+
<RootNamespace>TestingKeepAlive.Console</RootNamespace>
10+
<AssemblyName>TestingKeepAlive.Console</AssemblyName>
11+
<TargetFrameworkVersion>v4.6.1</TargetFrameworkVersion>
12+
<FileAlignment>512</FileAlignment>
13+
<AutoGenerateBindingRedirects>true</AutoGenerateBindingRedirects>
14+
<Deterministic>true</Deterministic>
15+
</PropertyGroup>
16+
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
17+
<PlatformTarget>AnyCPU</PlatformTarget>
18+
<DebugSymbols>true</DebugSymbols>
19+
<DebugType>full</DebugType>
20+
<Optimize>false</Optimize>
21+
<OutputPath>bin\Debug\</OutputPath>
22+
<DefineConstants>DEBUG;TRACE</DefineConstants>
23+
<ErrorReport>prompt</ErrorReport>
24+
<WarningLevel>4</WarningLevel>
25+
</PropertyGroup>
26+
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
27+
<PlatformTarget>AnyCPU</PlatformTarget>
28+
<DebugType>pdbonly</DebugType>
29+
<Optimize>true</Optimize>
30+
<OutputPath>bin\Release\</OutputPath>
31+
<DefineConstants>TRACE</DefineConstants>
32+
<ErrorReport>prompt</ErrorReport>
33+
<WarningLevel>4</WarningLevel>
34+
</PropertyGroup>
35+
<ItemGroup>
36+
<Reference Include="System" />
37+
<Reference Include="System.Core" />
38+
<Reference Include="System.Xml.Linq" />
39+
<Reference Include="System.Data.DataSetExtensions" />
40+
<Reference Include="Microsoft.CSharp" />
41+
<Reference Include="System.Data" />
42+
<Reference Include="System.Net.Http" />
43+
<Reference Include="System.Xml" />
44+
</ItemGroup>
45+
<ItemGroup>
46+
<Compile Include="Program.cs" />
47+
<Compile Include="Properties\AssemblyInfo.cs" />
48+
</ItemGroup>
49+
<ItemGroup>
50+
<None Include="App.config" />
51+
</ItemGroup>
52+
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
53+
</Project>

src/TestingKeepAlive.Web/Config.cs

Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
using System.Linq;
2+
using OpenRasta.Codecs.Newtonsoft.Json;
3+
using OpenRasta.Configuration;
4+
using OpenRasta.Hosting.Katana;
5+
using OpenRasta.Web;
6+
using Owin;
7+
8+
namespace TestingKeepAlive.Web
9+
{
10+
public class Config
11+
{
12+
public void Configuration(IAppBuilder app)
13+
{
14+
var openRastaConfiguration = new OpenRasta();
15+
16+
app.UseOpenRasta(openRastaConfiguration);
17+
}
18+
19+
class OpenRasta : IConfigurationSource
20+
{
21+
public void Configure()
22+
{
23+
ResourceSpace.Has
24+
.ResourcesOfType<Resource>()
25+
.AtUri("/")
26+
.HandledBy<Handler>()
27+
.TranscodedBy<NewtonsoftJsonCodec>();
28+
}
29+
}
30+
31+
class Resource
32+
{
33+
public int[] Data { get; set; }
34+
}
35+
36+
class Handler
37+
{
38+
public Resource Get() => new Resource
39+
{
40+
Data = Enumerable.Range(1, 10000).ToArray()
41+
};
42+
43+
public OperationResult Post(Resource resource) => new OperationResult.NoContent();
44+
}
45+
46+
}
47+
}
Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
using System.Reflection;
2+
using System.Runtime.InteropServices;
3+
using Microsoft.Owin;
4+
using TestingKeepAlive.Web;
5+
6+
// General Information about an assembly is controlled through the following
7+
// set of attributes. Change these attribute values to modify the information
8+
// associated with an assembly.
9+
[assembly: AssemblyTitle("TestingKeepAlive")]
10+
[assembly: AssemblyDescription("")]
11+
[assembly: AssemblyConfiguration("")]
12+
[assembly: AssemblyCompany("")]
13+
[assembly: AssemblyProduct("TestingKeepAlive")]
14+
[assembly: AssemblyCopyright("Copyright © 2019")]
15+
[assembly: AssemblyTrademark("")]
16+
[assembly: AssemblyCulture("")]
17+
18+
// Setting ComVisible to false makes the types in this assembly not visible
19+
// to COM components. If you need to access a type in this assembly from
20+
// COM, set the ComVisible attribute to true on that type.
21+
[assembly: ComVisible(false)]
22+
23+
// The following GUID is for the ID of the typelib if this project is exposed to COM
24+
[assembly: Guid("24b7b587-f7e7-4f56-bea3-88f1a87c648c")]
25+
26+
// Version information for an assembly consists of the following four values:
27+
//
28+
// Major Version
29+
// Minor Version
30+
// Build Number
31+
// Revision
32+
//
33+
// You can specify all the values or you can default the Revision and Build Numbers
34+
// by using the '*' as shown below:
35+
[assembly: AssemblyVersion("1.0.0.0")]
36+
[assembly: AssemblyFileVersion("1.0.0.0")]
37+
38+
[assembly: OwinStartup(typeof(Config))]

0 commit comments

Comments
 (0)