Skip to content
This repository was archived by the owner on Jul 9, 2023. It is now read-only.

Commit d4a6d2b

Browse files
Merge pull request #554 from jmh76/issue-553
Issue 553
2 parents 352de4a + 8d39aad commit d4a6d2b

18 files changed

+773
-142
lines changed

src/Titanium.Web.Proxy/.editorconfig

Lines changed: 124 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,124 @@
1+
# To learn more about .editorconfig see https://aka.ms/editorconfigdocs
2+
###############################
3+
# Core EditorConfig Options #
4+
###############################
5+
root = true
6+
# All files
7+
[*]
8+
indent_style = space
9+
# Code files
10+
[*.{cs,csx,vb,vbx}]
11+
indent_size = 4
12+
insert_final_newline = true
13+
charset = utf-8-bom
14+
###############################
15+
# .NET Coding Conventions #
16+
###############################
17+
[*.{cs,vb}]
18+
# Organize usings
19+
dotnet_sort_system_directives_first = true
20+
# this. preferences
21+
dotnet_style_qualification_for_field = false:silent
22+
dotnet_style_qualification_for_property = false:silent
23+
dotnet_style_qualification_for_method = false:silent
24+
dotnet_style_qualification_for_event = false:silent
25+
# Language keywords vs BCL types preferences
26+
dotnet_style_predefined_type_for_locals_parameters_members = true:silent
27+
dotnet_style_predefined_type_for_member_access = true:silent
28+
# Parentheses preferences
29+
dotnet_style_parentheses_in_arithmetic_binary_operators = always_for_clarity:silent
30+
dotnet_style_parentheses_in_relational_binary_operators = always_for_clarity:silent
31+
dotnet_style_parentheses_in_other_binary_operators = always_for_clarity:silent
32+
dotnet_style_parentheses_in_other_operators = never_if_unnecessary:silent
33+
# Modifier preferences
34+
dotnet_style_require_accessibility_modifiers = for_non_interface_members:silent
35+
dotnet_style_readonly_field = true:suggestion
36+
# Expression-level preferences
37+
dotnet_style_object_initializer = true:suggestion
38+
dotnet_style_collection_initializer = true:suggestion
39+
dotnet_style_explicit_tuple_names = true:suggestion
40+
dotnet_style_null_propagation = true:suggestion
41+
dotnet_style_coalesce_expression = true:suggestion
42+
dotnet_style_prefer_is_null_check_over_reference_equality_method = true:silent
43+
dotnet_prefer_inferred_tuple_names = true:suggestion
44+
dotnet_prefer_inferred_anonymous_type_member_names = true:suggestion
45+
dotnet_style_prefer_auto_properties = true:silent
46+
dotnet_style_prefer_conditional_expression_over_assignment = true:silent
47+
dotnet_style_prefer_conditional_expression_over_return = true:silent
48+
###############################
49+
# Naming Conventions #
50+
###############################
51+
# Style Definitions
52+
dotnet_naming_style.pascal_case_style.capitalization = pascal_case
53+
# Use PascalCase for constant fields
54+
dotnet_naming_rule.constant_fields_should_be_pascal_case.severity = suggestion
55+
dotnet_naming_rule.constant_fields_should_be_pascal_case.symbols = constant_fields
56+
dotnet_naming_rule.constant_fields_should_be_pascal_case.style = pascal_case_style
57+
dotnet_naming_symbols.constant_fields.applicable_kinds = field
58+
dotnet_naming_symbols.constant_fields.applicable_accessibilities = *
59+
dotnet_naming_symbols.constant_fields.required_modifiers = const
60+
###############################
61+
# C# Coding Conventions #
62+
###############################
63+
[*.cs]
64+
# var preferences
65+
csharp_style_var_for_built_in_types = true:silent
66+
csharp_style_var_when_type_is_apparent = true:silent
67+
csharp_style_var_elsewhere = true:silent
68+
# Expression-bodied members
69+
csharp_style_expression_bodied_methods = false:silent
70+
csharp_style_expression_bodied_constructors = false:silent
71+
csharp_style_expression_bodied_operators = false:silent
72+
csharp_style_expression_bodied_properties = true:silent
73+
csharp_style_expression_bodied_indexers = true:silent
74+
csharp_style_expression_bodied_accessors = true:silent
75+
# Pattern matching preferences
76+
csharp_style_pattern_matching_over_is_with_cast_check = true:suggestion
77+
csharp_style_pattern_matching_over_as_with_null_check = true:suggestion
78+
# Null-checking preferences
79+
csharp_style_throw_expression = true:suggestion
80+
csharp_style_conditional_delegate_call = true:suggestion
81+
# Modifier preferences
82+
csharp_preferred_modifier_order = public,private,protected,internal,static,extern,new,virtual,abstract,sealed,override,readonly,unsafe,volatile,async:suggestion
83+
# Expression-level preferences
84+
csharp_prefer_braces = true:silent
85+
csharp_style_deconstructed_variable_declaration = true:suggestion
86+
csharp_prefer_simple_default_expression = true:suggestion
87+
csharp_style_pattern_local_over_anonymous_function = true:suggestion
88+
csharp_style_inlined_variable_declaration = true:suggestion
89+
###############################
90+
# C# Formatting Rules #
91+
###############################
92+
# New line preferences
93+
csharp_new_line_before_open_brace = all
94+
csharp_new_line_before_else = true
95+
csharp_new_line_before_catch = true
96+
csharp_new_line_before_finally = true
97+
csharp_new_line_before_members_in_object_initializers = true
98+
csharp_new_line_before_members_in_anonymous_types = true
99+
csharp_new_line_between_query_expression_clauses = true
100+
# Indentation preferences
101+
csharp_indent_case_contents = true
102+
csharp_indent_switch_labels = true
103+
csharp_indent_labels = flush_left
104+
# Space preferences
105+
csharp_space_after_cast = false
106+
csharp_space_after_keywords_in_control_flow_statements = true
107+
csharp_space_between_method_call_parameter_list_parentheses = false
108+
csharp_space_between_method_declaration_parameter_list_parentheses = false
109+
csharp_space_between_parentheses = false
110+
csharp_space_before_colon_in_inheritance_clause = true
111+
csharp_space_after_colon_in_inheritance_clause = true
112+
csharp_space_around_binary_operators = before_and_after
113+
csharp_space_between_method_declaration_empty_parameter_list_parentheses = false
114+
csharp_space_between_method_call_name_and_opening_parenthesis = false
115+
csharp_space_between_method_call_empty_parameter_list_parentheses = false
116+
# Wrapping preferences
117+
csharp_preserve_single_line_statements = true
118+
csharp_preserve_single_line_blocks = true
119+
###############################
120+
# VB Coding Conventions #
121+
###############################
122+
[*.vb]
123+
# Modifier preferences
124+
visual_basic_preferred_modifier_order = Partial,Default,Private,Protected,Public,Friend,NotOverridable,Overridable,MustOverride,Overloads,Overrides,MustInherit,NotInheritable,Static,Shared,Shadows,ReadOnly,WriteOnly,Dim,Const,WithEvents,Widening,Narrowing,Custom,Async:suggestion

src/Titanium.Web.Proxy/Http/HttpWebClient.cs

Lines changed: 11 additions & 60 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
using System;
1+
using System;
22
using System.IO;
33
using System.Net;
44
using System.Text;
@@ -127,40 +127,18 @@ await writer.WriteLineAsync(Request.CreateRequestLine(Request.Method,
127127

128128
await writer.WriteAsync(headerBuilder.ToString(), cancellationToken);
129129

130-
if (enable100ContinueBehaviour)
130+
if (enable100ContinueBehaviour && Request.ExpectContinue)
131131
{
132-
if (Request.ExpectContinue)
132+
// wait for expectation response from server
133+
await ReceiveResponse(cancellationToken);
134+
135+
if (Response.StatusCode == (int)HttpStatusCode.Continue)
136+
{
137+
Request.ExpectationSucceeded = true;
138+
}
139+
else
133140
{
134-
string httpStatus;
135-
try
136-
{
137-
httpStatus = await Connection.Stream.ReadLineAsync(cancellationToken);
138-
if (httpStatus == null)
139-
{
140-
throw new ServerConnectionException("Server connection was closed.");
141-
}
142-
}
143-
catch (Exception e) when (!(e is ServerConnectionException))
144-
{
145-
throw new ServerConnectionException("Server connection was closed.");
146-
}
147-
148-
Response.ParseResponseLine(httpStatus, out _, out int responseStatusCode,
149-
out string responseStatusDescription);
150-
151-
// find if server is willing for expect continue
152-
if (responseStatusCode == (int)HttpStatusCode.Continue
153-
&& responseStatusDescription.EqualsIgnoreCase("continue"))
154-
{
155-
Request.Is100Continue = true;
156-
await Connection.Stream.ReadLineAsync(cancellationToken);
157-
}
158-
else if (responseStatusCode == (int)HttpStatusCode.ExpectationFailed
159-
&& responseStatusDescription.EqualsIgnoreCase("expectation failed"))
160-
{
161-
Request.ExpectationFailed = true;
162-
await Connection.Stream.ReadLineAsync(cancellationToken);
163-
}
141+
Request.ExpectationFailed = true;
164142
}
165143
}
166144
}
@@ -202,33 +180,6 @@ internal async Task ReceiveResponse(CancellationToken cancellationToken)
202180
Response.StatusCode = statusCode;
203181
Response.StatusDescription = statusDescription;
204182

205-
// For HTTP 1.1 comptibility server may send expect-continue even if not asked for it in request
206-
if (Response.StatusCode == (int)HttpStatusCode.Continue
207-
&& Response.StatusDescription.EqualsIgnoreCase("continue"))
208-
{
209-
// Read the next line after 100-continue
210-
Response.Is100Continue = true;
211-
Response.StatusCode = 0;
212-
await Connection.Stream.ReadLineAsync(cancellationToken);
213-
214-
// now receive response
215-
await ReceiveResponse(cancellationToken);
216-
return;
217-
}
218-
219-
if (Response.StatusCode == (int)HttpStatusCode.ExpectationFailed
220-
&& Response.StatusDescription.EqualsIgnoreCase("expectation failed"))
221-
{
222-
// read next line after expectation failed response
223-
Response.ExpectationFailed = true;
224-
Response.StatusCode = 0;
225-
await Connection.Stream.ReadLineAsync(cancellationToken);
226-
227-
// now receive response
228-
await ReceiveResponse(cancellationToken);
229-
return;
230-
}
231-
232183
// Read the response headers in to unique and non-unique header collections
233184
await HeaderParser.ReadHeaders(Connection.Stream, Response.Headers, cancellationToken);
234185
}

src/Titanium.Web.Proxy/Http/Request.cs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -123,12 +123,12 @@ public bool UpgradeToWebSocket
123123
}
124124

125125
/// <summary>
126-
/// Did server responsed positively for 100 continue request?
126+
/// Did server respond positively for 100 continue request?
127127
/// </summary>
128-
public bool Is100Continue { get; internal set; }
128+
public bool ExpectationSucceeded { get; internal set; }
129129

130130
/// <summary>
131-
/// Did server responsed negatively for the request for 100 continue?
131+
/// Did server respond negatively for 100 continue request?
132132
/// </summary>
133133
public bool ExpectationFailed { get; internal set; }
134134

src/Titanium.Web.Proxy/Http/Response.cs

Lines changed: 0 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -92,16 +92,6 @@ public bool KeepAlive
9292
}
9393
}
9494

95-
/// <summary>
96-
/// Is response 100-continue
97-
/// </summary>
98-
public bool Is100Continue { get; internal set; }
99-
100-
/// <summary>
101-
/// expectation failed returned by server?
102-
/// </summary>
103-
public bool ExpectationFailed { get; internal set; }
104-
10595
/// <summary>
10696
/// Gets the header text.
10797
/// </summary>

src/Titanium.Web.Proxy/Network/Tcp/TcpConnectionFactory.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -279,7 +279,7 @@ private async Task<TcpServerConnection> createServerConnection(string remoteHost
279279
};
280280

281281
//linux has a bug with socket reuse in .net core.
282-
if (proxyServer.ReuseSocket && RunTime.IsWindows || RunTime.IsRunningOnMono)
282+
if (proxyServer.ReuseSocket && (RunTime.IsWindows || RunTime.IsRunningOnMono))
283283
{
284284
tcpClient.Client.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.ReuseAddress, true);
285285
}

src/Titanium.Web.Proxy/Properties/AssemblyInfo.cs

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,12 @@
2020
"de7f3ba0bdad35ec2d6057ee1846091b34be2abc3f97dc7e72c16fd4958c15126b12923df76964" +
2121
"7d84922c3f4f3b80ee0ae8e4cb40bc1973b782afb90bb00519fd16adf960f217e23696e7c31654" +
2222
"01d0acd6")]
23+
[assembly: InternalsVisibleTo("Titanium.Web.Proxy.IntegrationTests, PublicKey=" +
24+
"0024000004800000940000000602000000240000525341310004000001000100e7368e0ccc717e" +
25+
"eb4d57d35ad6a8305cbbed14faa222e13869405e92c83856266d400887d857005f1393ffca2b92" +
26+
"de7f3ba0bdad35ec2d6057ee1846091b34be2abc3f97dc7e72c16fd4958c15126b12923df76964" +
27+
"7d84922c3f4f3b80ee0ae8e4cb40bc1973b782afb90bb00519fd16adf960f217e23696e7c31654" +
28+
"01d0acd6")]
2329

2430
// Setting ComVisible to false makes the types in this assembly not visible
2531
// to COM components. If you need to access a type in this assembly from

src/Titanium.Web.Proxy/ProxyServer.cs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
using System;
1+
using System;
22
using System.Collections.Generic;
33
using System.Linq;
44
using System.Net;
@@ -152,7 +152,7 @@ public ProxyServer(string rootCertificateName, string rootCertificateIssuerName,
152152

153153
/// <summary>
154154
/// Does this proxy uses the HTTP protocol 100 continue behaviour strictly?
155-
/// Broken 100 contunue implementations on server/client may cause problems if enabled.
155+
/// Broken 100 continue implementations on server/client may cause problems if enabled.
156156
/// Defaults to false.
157157
/// </summary>
158158
public bool Enable100ContinueBehaviour { get; set; }

src/Titanium.Web.Proxy/RequestHandler.cs

Lines changed: 24 additions & 50 deletions
Original file line numberDiff line numberDiff line change
@@ -169,8 +169,11 @@ await clientStreamWriter.WriteResponseAsync(args.HttpClient.Response,
169169

170170
if (request.CancelRequest)
171171
{
172-
// syphon out the request body from client before setting the new body
173-
await args.SyphonOutBodyAsync(true, cancellationToken);
172+
if (!(Enable100ContinueBehaviour && request.ExpectContinue))
173+
{
174+
// syphon out the request body from client before setting the new body
175+
await args.SyphonOutBodyAsync(true, cancellationToken);
176+
}
174177

175178
await handleHttpSessionResponse(args);
176179

@@ -318,71 +321,42 @@ private async Task handleHttpSessionRequest(TcpServerConnection connection, Sess
318321

319322
var body = request.CompressBodyAndUpdateContentLength();
320323

321-
// if expect continue is enabled then send the headers first
322-
// and see if server would return 100 conitinue
323-
if (request.ExpectContinue)
324-
{
325-
args.HttpClient.SetConnection(connection);
326-
await args.HttpClient.SendRequest(Enable100ContinueBehaviour, args.IsTransparent,
327-
cancellationToken);
328-
}
324+
// set the connection and send request headers
325+
args.HttpClient.SetConnection(connection);
326+
await args.HttpClient.SendRequest(Enable100ContinueBehaviour, args.IsTransparent,
327+
cancellationToken);
329328

330-
// If 100 continue was the response inform that to the client
331-
if (Enable100ContinueBehaviour)
329+
// If a successful 100 continue request was made, inform that to the client and reset response
330+
if (request.ExpectationSucceeded)
332331
{
333332
var clientStreamWriter = args.ProxyClient.ClientStreamWriter;
334-
335-
if (request.Is100Continue)
336-
{
337-
await clientStreamWriter.WriteResponseStatusAsync(args.HttpClient.Response.HttpVersion,
338-
(int)HttpStatusCode.Continue, "Continue", cancellationToken);
339-
await clientStreamWriter.WriteLineAsync(cancellationToken);
340-
}
341-
else if (request.ExpectationFailed)
342-
{
343-
await clientStreamWriter.WriteResponseStatusAsync(args.HttpClient.Response.HttpVersion,
344-
(int)HttpStatusCode.ExpectationFailed, "Expectation Failed", cancellationToken);
345-
await clientStreamWriter.WriteLineAsync(cancellationToken);
346-
}
333+
var response = args.HttpClient.Response;
334+
await clientStreamWriter.WriteResponseStatusAsync(response.HttpVersion, response.StatusCode,
335+
response.StatusDescription, cancellationToken);
336+
await clientStreamWriter.WriteHeadersAsync(response.Headers, cancellationToken: cancellationToken);
337+
await args.ClearResponse(cancellationToken);
347338
}
348339

349-
// If expect continue is not enabled then set the connectio and send request headers
350-
if (!request.ExpectContinue)
351-
{
352-
args.HttpClient.SetConnection(connection);
353-
await args.HttpClient.SendRequest(Enable100ContinueBehaviour, args.IsTransparent,
354-
cancellationToken);
355-
}
356-
357-
// check if content-length is > 0
358-
if (request.ContentLength > 0)
340+
// send body to server if available
341+
if (request.HasBody)
359342
{
360343
if (request.IsBodyRead)
361344
{
362345
var writer = args.HttpClient.Connection.StreamWriter;
363346
await writer.WriteBodyAsync(body, request.IsChunked, cancellationToken);
364347
}
365-
else
348+
else if (!request.ExpectationFailed)
366349
{
367-
if (!request.ExpectationFailed)
368-
{
369-
if (request.HasBody)
370-
{
371-
HttpWriter writer = args.HttpClient.Connection.StreamWriter;
372-
await args.CopyRequestBodyAsync(writer, TransformationMode.None, cancellationToken);
373-
}
374-
}
350+
// get the request body unless an unsuccessful 100 continue request was made
351+
HttpWriter writer = args.HttpClient.Connection.StreamWriter;
352+
await args.CopyRequestBodyAsync(writer, TransformationMode.None, cancellationToken);
375353
}
376354
}
377355

378356
args.TimeLine["Request Sent"] = DateTime.Now;
379357

380-
// If not expectation failed response was returned by server then parse response
381-
if (!request.ExpectationFailed)
382-
{
383-
await handleHttpSessionResponse(args);
384-
}
385-
358+
// parse and send response
359+
await handleHttpSessionResponse(args);
386360
}
387361

388362
/// <summary>

0 commit comments

Comments
 (0)