Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Contribute to GitLab
Sign in / Register
Toggle navigation
T
Titanium-Web-Proxy
Project
Project
Details
Activity
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Board
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
Administrator
Titanium-Web-Proxy
Commits
9fcf5c3b
Commit
9fcf5c3b
authored
Feb 25, 2019
by
jmh76
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Fixing Expect 100-continue requests #553
parent
4e203c3a
Hide whitespace changes
Inline
Side-by-side
Showing
19 changed files
with
810 additions
and
142 deletions
+810
-142
.editorconfig
src/Titanium.Web.Proxy/.editorconfig
+124
-0
HttpWebClient.cs
src/Titanium.Web.Proxy/Http/HttpWebClient.cs
+11
-60
Request.cs
src/Titanium.Web.Proxy/Http/Request.cs
+3
-3
Response.cs
src/Titanium.Web.Proxy/Http/Response.cs
+0
-10
TcpConnectionFactory.cs
src/Titanium.Web.Proxy/Network/Tcp/TcpConnectionFactory.cs
+1
-1
AssemblyInfo.cs
src/Titanium.Web.Proxy/Properties/AssemblyInfo.cs
+6
-0
ProxyServer.cs
src/Titanium.Web.Proxy/ProxyServer.cs
+2
-2
RequestHandler.cs
src/Titanium.Web.Proxy/RequestHandler.cs
+24
-50
ResponseHandler.cs
src/Titanium.Web.Proxy/ResponseHandler.cs
+8
-14
.editorconfig
tests/Titanium.Web.Proxy.IntegrationTests/.editorconfig
+124
-0
ExpectContinueTests.cs
...itanium.Web.Proxy.IntegrationTests/ExpectContinueTests.cs
+138
-0
HttpContinueClient.cs
....Web.Proxy.IntegrationTests/Helpers/HttpContinueClient.cs
+67
-0
HttpContinueServer.cs
....Web.Proxy.IntegrationTests/Helpers/HttpContinueServer.cs
+93
-0
HttpMessageParsing.cs
....Web.Proxy.IntegrationTests/Helpers/HttpMessageParsing.cs
+113
-0
TestServer.cs
...s/Titanium.Web.Proxy.IntegrationTests/Setup/TestServer.cs
+26
-2
StrongNameKey.snk
tests/Titanium.Web.Proxy.IntegrationTests/StrongNameKey.snk
+0
-0
Titanium.Web.Proxy.IntegrationTests.csproj
...tegrationTests/Titanium.Web.Proxy.IntegrationTests.csproj
+2
-0
Titanium.Web.Proxy.IntegrationTests.csproj.bak
...ationTests/Titanium.Web.Proxy.IntegrationTests.csproj.bak
+27
-0
Titanium.Web.Proxy.IntegrationTests.sln
....IntegrationTests/Titanium.Web.Proxy.IntegrationTests.sln
+41
-0
No files found.
src/Titanium.Web.Proxy/.editorconfig
0 → 100644
View file @
9fcf5c3b
# To learn more about .editorconfig see https://aka.ms/editorconfigdocs
###############################
# Core EditorConfig Options #
###############################
root = true
# All files
[*]
indent_style = space
# Code files
[*.{cs,csx,vb,vbx}]
indent_size = 4
insert_final_newline = true
charset = utf-8-bom
###############################
# .NET Coding Conventions #
###############################
[*.{cs,vb}]
# Organize usings
dotnet_sort_system_directives_first = true
# this. preferences
dotnet_style_qualification_for_field = false:silent
dotnet_style_qualification_for_property = false:silent
dotnet_style_qualification_for_method = false:silent
dotnet_style_qualification_for_event = false:silent
# Language keywords vs BCL types preferences
dotnet_style_predefined_type_for_locals_parameters_members = true:silent
dotnet_style_predefined_type_for_member_access = true:silent
# Parentheses preferences
dotnet_style_parentheses_in_arithmetic_binary_operators = always_for_clarity:silent
dotnet_style_parentheses_in_relational_binary_operators = always_for_clarity:silent
dotnet_style_parentheses_in_other_binary_operators = always_for_clarity:silent
dotnet_style_parentheses_in_other_operators = never_if_unnecessary:silent
# Modifier preferences
dotnet_style_require_accessibility_modifiers = for_non_interface_members:silent
dotnet_style_readonly_field = true:suggestion
# Expression-level preferences
dotnet_style_object_initializer = true:suggestion
dotnet_style_collection_initializer = true:suggestion
dotnet_style_explicit_tuple_names = true:suggestion
dotnet_style_null_propagation = true:suggestion
dotnet_style_coalesce_expression = true:suggestion
dotnet_style_prefer_is_null_check_over_reference_equality_method = true:silent
dotnet_prefer_inferred_tuple_names = true:suggestion
dotnet_prefer_inferred_anonymous_type_member_names = true:suggestion
dotnet_style_prefer_auto_properties = true:silent
dotnet_style_prefer_conditional_expression_over_assignment = true:silent
dotnet_style_prefer_conditional_expression_over_return = true:silent
###############################
# Naming Conventions #
###############################
# Style Definitions
dotnet_naming_style.pascal_case_style.capitalization = pascal_case
# Use PascalCase for constant fields
dotnet_naming_rule.constant_fields_should_be_pascal_case.severity = suggestion
dotnet_naming_rule.constant_fields_should_be_pascal_case.symbols = constant_fields
dotnet_naming_rule.constant_fields_should_be_pascal_case.style = pascal_case_style
dotnet_naming_symbols.constant_fields.applicable_kinds = field
dotnet_naming_symbols.constant_fields.applicable_accessibilities = *
dotnet_naming_symbols.constant_fields.required_modifiers = const
###############################
# C# Coding Conventions #
###############################
[*.cs]
# var preferences
csharp_style_var_for_built_in_types = true:silent
csharp_style_var_when_type_is_apparent = true:silent
csharp_style_var_elsewhere = true:silent
# Expression-bodied members
csharp_style_expression_bodied_methods = false:silent
csharp_style_expression_bodied_constructors = false:silent
csharp_style_expression_bodied_operators = false:silent
csharp_style_expression_bodied_properties = true:silent
csharp_style_expression_bodied_indexers = true:silent
csharp_style_expression_bodied_accessors = true:silent
# Pattern matching preferences
csharp_style_pattern_matching_over_is_with_cast_check = true:suggestion
csharp_style_pattern_matching_over_as_with_null_check = true:suggestion
# Null-checking preferences
csharp_style_throw_expression = true:suggestion
csharp_style_conditional_delegate_call = true:suggestion
# Modifier preferences
csharp_preferred_modifier_order = public,private,protected,internal,static,extern,new,virtual,abstract,sealed,override,readonly,unsafe,volatile,async:suggestion
# Expression-level preferences
csharp_prefer_braces = true:silent
csharp_style_deconstructed_variable_declaration = true:suggestion
csharp_prefer_simple_default_expression = true:suggestion
csharp_style_pattern_local_over_anonymous_function = true:suggestion
csharp_style_inlined_variable_declaration = true:suggestion
###############################
# C# Formatting Rules #
###############################
# New line preferences
csharp_new_line_before_open_brace = all
csharp_new_line_before_else = true
csharp_new_line_before_catch = true
csharp_new_line_before_finally = true
csharp_new_line_before_members_in_object_initializers = true
csharp_new_line_before_members_in_anonymous_types = true
csharp_new_line_between_query_expression_clauses = true
# Indentation preferences
csharp_indent_case_contents = true
csharp_indent_switch_labels = true
csharp_indent_labels = flush_left
# Space preferences
csharp_space_after_cast = false
csharp_space_after_keywords_in_control_flow_statements = true
csharp_space_between_method_call_parameter_list_parentheses = false
csharp_space_between_method_declaration_parameter_list_parentheses = false
csharp_space_between_parentheses = false
csharp_space_before_colon_in_inheritance_clause = true
csharp_space_after_colon_in_inheritance_clause = true
csharp_space_around_binary_operators = before_and_after
csharp_space_between_method_declaration_empty_parameter_list_parentheses = false
csharp_space_between_method_call_name_and_opening_parenthesis = false
csharp_space_between_method_call_empty_parameter_list_parentheses = false
# Wrapping preferences
csharp_preserve_single_line_statements = true
csharp_preserve_single_line_blocks = true
###############################
# VB Coding Conventions #
###############################
[*.vb]
# Modifier preferences
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
View file @
9fcf5c3b
using
System
;
using
System
;
using
System.IO
;
using
System.Net
;
using
System.Text
;
...
...
@@ -127,40 +127,18 @@ namespace Titanium.Web.Proxy.Http
await
writer
.
WriteAsync
(
headerBuilder
.
ToString
(),
cancellationToken
);
if
(
enable100ContinueBehaviour
)
if
(
enable100ContinueBehaviour
&&
Request
.
ExpectContinue
)
{
if
(
Request
.
ExpectContinue
)
// wait for expectation response from server
await
ReceiveResponse
(
cancellationToken
);
if
(
Response
.
StatusCode
==
(
int
)
HttpStatusCode
.
Continue
)
{
Request
.
ExpectationSucceeded
=
true
;
}
else
{
string
httpStatus
;
try
{
httpStatus
=
await
Connection
.
Stream
.
ReadLineAsync
(
cancellationToken
);
if
(
httpStatus
==
null
)
{
throw
new
ServerConnectionException
(
"Server connection was closed."
);
}
}
catch
(
Exception
e
)
when
(!(
e
is
ServerConnectionException
))
{
throw
new
ServerConnectionException
(
"Server connection was closed."
);
}
Response
.
ParseResponseLine
(
httpStatus
,
out
_
,
out
int
responseStatusCode
,
out
string
responseStatusDescription
);
// find if server is willing for expect continue
if
(
responseStatusCode
==
(
int
)
HttpStatusCode
.
Continue
&&
responseStatusDescription
.
EqualsIgnoreCase
(
"continue"
))
{
Request
.
Is100Continue
=
true
;
await
Connection
.
Stream
.
ReadLineAsync
(
cancellationToken
);
}
else
if
(
responseStatusCode
==
(
int
)
HttpStatusCode
.
ExpectationFailed
&&
responseStatusDescription
.
EqualsIgnoreCase
(
"expectation failed"
))
{
Request
.
ExpectationFailed
=
true
;
await
Connection
.
Stream
.
ReadLineAsync
(
cancellationToken
);
}
Request
.
ExpectationFailed
=
true
;
}
}
}
...
...
@@ -202,33 +180,6 @@ namespace Titanium.Web.Proxy.Http
Response
.
StatusCode
=
statusCode
;
Response
.
StatusDescription
=
statusDescription
;
// For HTTP 1.1 comptibility server may send expect-continue even if not asked for it in request
if
(
Response
.
StatusCode
==
(
int
)
HttpStatusCode
.
Continue
&&
Response
.
StatusDescription
.
EqualsIgnoreCase
(
"continue"
))
{
// Read the next line after 100-continue
Response
.
Is100Continue
=
true
;
Response
.
StatusCode
=
0
;
await
Connection
.
Stream
.
ReadLineAsync
(
cancellationToken
);
// now receive response
await
ReceiveResponse
(
cancellationToken
);
return
;
}
if
(
Response
.
StatusCode
==
(
int
)
HttpStatusCode
.
ExpectationFailed
&&
Response
.
StatusDescription
.
EqualsIgnoreCase
(
"expectation failed"
))
{
// read next line after expectation failed response
Response
.
ExpectationFailed
=
true
;
Response
.
StatusCode
=
0
;
await
Connection
.
Stream
.
ReadLineAsync
(
cancellationToken
);
// now receive response
await
ReceiveResponse
(
cancellationToken
);
return
;
}
// Read the response headers in to unique and non-unique header collections
await
HeaderParser
.
ReadHeaders
(
Connection
.
Stream
,
Response
.
Headers
,
cancellationToken
);
}
...
...
src/Titanium.Web.Proxy/Http/Request.cs
View file @
9fcf5c3b
...
...
@@ -123,12 +123,12 @@ namespace Titanium.Web.Proxy.Http
}
/// <summary>
/// Did server respon
se
d positively for 100 continue request?
/// Did server respond positively for 100 continue request?
/// </summary>
public
bool
Is100Continue
{
get
;
internal
set
;
}
public
bool
ExpectationSucceeded
{
get
;
internal
set
;
}
/// <summary>
/// Did server respon
sed negatively for the request for 100 continue
?
/// Did server respon
d negatively for 100 continue request
?
/// </summary>
public
bool
ExpectationFailed
{
get
;
internal
set
;
}
...
...
src/Titanium.Web.Proxy/Http/Response.cs
View file @
9fcf5c3b
...
...
@@ -92,16 +92,6 @@ namespace Titanium.Web.Proxy.Http
}
}
/// <summary>
/// Is response 100-continue
/// </summary>
public
bool
Is100Continue
{
get
;
internal
set
;
}
/// <summary>
/// expectation failed returned by server?
/// </summary>
public
bool
ExpectationFailed
{
get
;
internal
set
;
}
/// <summary>
/// Gets the header text.
/// </summary>
...
...
src/Titanium.Web.Proxy/Network/Tcp/TcpConnectionFactory.cs
View file @
9fcf5c3b
...
...
@@ -279,7 +279,7 @@ namespace Titanium.Web.Proxy.Network.Tcp
};
//linux has a bug with socket reuse in .net core.
if
(
proxyServer
.
ReuseSocket
&&
RunTime
.
IsWindows
||
RunTime
.
IsRunningOnMono
)
if
(
proxyServer
.
ReuseSocket
&&
(
RunTime
.
IsWindows
||
RunTime
.
IsRunningOnMono
)
)
{
tcpClient
.
Client
.
SetSocketOption
(
SocketOptionLevel
.
Socket
,
SocketOptionName
.
ReuseAddress
,
true
);
}
...
...
src/Titanium.Web.Proxy/Properties/AssemblyInfo.cs
View file @
9fcf5c3b
...
...
@@ -20,6 +20,12 @@ using System.Runtime.InteropServices;
"de7f3ba0bdad35ec2d6057ee1846091b34be2abc3f97dc7e72c16fd4958c15126b12923df76964"
+
"7d84922c3f4f3b80ee0ae8e4cb40bc1973b782afb90bb00519fd16adf960f217e23696e7c31654"
+
"01d0acd6"
)]
[
assembly
:
InternalsVisibleTo
(
"Titanium.Web.Proxy.IntegrationTests, PublicKey="
+
"0024000004800000940000000602000000240000525341310004000001000100e7368e0ccc717e"
+
"eb4d57d35ad6a8305cbbed14faa222e13869405e92c83856266d400887d857005f1393ffca2b92"
+
"de7f3ba0bdad35ec2d6057ee1846091b34be2abc3f97dc7e72c16fd4958c15126b12923df76964"
+
"7d84922c3f4f3b80ee0ae8e4cb40bc1973b782afb90bb00519fd16adf960f217e23696e7c31654"
+
"01d0acd6"
)]
// Setting ComVisible to false makes the types in this assembly not visible
// to COM components. If you need to access a type in this assembly from
...
...
src/Titanium.Web.Proxy/ProxyServer.cs
View file @
9fcf5c3b
using
System
;
using
System
;
using
System.Collections.Generic
;
using
System.Linq
;
using
System.Net
;
...
...
@@ -152,7 +152,7 @@ namespace Titanium.Web.Proxy
/// <summary>
/// Does this proxy uses the HTTP protocol 100 continue behaviour strictly?
/// Broken 100 cont
u
nue implementations on server/client may cause problems if enabled.
/// Broken 100 cont
i
nue implementations on server/client may cause problems if enabled.
/// Defaults to false.
/// </summary>
public
bool
Enable100ContinueBehaviour
{
get
;
set
;
}
...
...
src/Titanium.Web.Proxy/RequestHandler.cs
View file @
9fcf5c3b
...
...
@@ -169,8 +169,11 @@ namespace Titanium.Web.Proxy
if
(
request
.
CancelRequest
)
{
// syphon out the request body from client before setting the new body
await
args
.
SyphonOutBodyAsync
(
true
,
cancellationToken
);
if
(!(
Enable100ContinueBehaviour
&&
request
.
ExpectContinue
))
{
// syphon out the request body from client before setting the new body
await
args
.
SyphonOutBodyAsync
(
true
,
cancellationToken
);
}
await
handleHttpSessionResponse
(
args
);
...
...
@@ -318,71 +321,42 @@ namespace Titanium.Web.Proxy
var
body
=
request
.
CompressBodyAndUpdateContentLength
();
// if expect continue is enabled then send the headers first
// and see if server would return 100 conitinue
if
(
request
.
ExpectContinue
)
{
args
.
HttpClient
.
SetConnection
(
connection
);
await
args
.
HttpClient
.
SendRequest
(
Enable100ContinueBehaviour
,
args
.
IsTransparent
,
cancellationToken
);
}
// set the connection and send request headers
args
.
HttpClient
.
SetConnection
(
connection
);
await
args
.
HttpClient
.
SendRequest
(
Enable100ContinueBehaviour
,
args
.
IsTransparent
,
cancellationToken
);
// If
100 continue was the response inform that to the client
if
(
Enable100ContinueBehaviour
)
// If
a successful 100 continue request was made, inform that to the client and reset response
if
(
request
.
ExpectationSucceeded
)
{
var
clientStreamWriter
=
args
.
ProxyClient
.
ClientStreamWriter
;
if
(
request
.
Is100Continue
)
{
await
clientStreamWriter
.
WriteResponseStatusAsync
(
args
.
HttpClient
.
Response
.
HttpVersion
,
(
int
)
HttpStatusCode
.
Continue
,
"Continue"
,
cancellationToken
);
await
clientStreamWriter
.
WriteLineAsync
(
cancellationToken
);
}
else
if
(
request
.
ExpectationFailed
)
{
await
clientStreamWriter
.
WriteResponseStatusAsync
(
args
.
HttpClient
.
Response
.
HttpVersion
,
(
int
)
HttpStatusCode
.
ExpectationFailed
,
"Expectation Failed"
,
cancellationToken
);
await
clientStreamWriter
.
WriteLineAsync
(
cancellationToken
);
}
var
response
=
args
.
HttpClient
.
Response
;
await
clientStreamWriter
.
WriteResponseStatusAsync
(
response
.
HttpVersion
,
response
.
StatusCode
,
response
.
StatusDescription
,
cancellationToken
);
await
clientStreamWriter
.
WriteHeadersAsync
(
response
.
Headers
,
cancellationToken
:
cancellationToken
);
await
args
.
ClearResponse
(
cancellationToken
);
}
// If expect continue is not enabled then set the connectio and send request headers
if
(!
request
.
ExpectContinue
)
{
args
.
HttpClient
.
SetConnection
(
connection
);
await
args
.
HttpClient
.
SendRequest
(
Enable100ContinueBehaviour
,
args
.
IsTransparent
,
cancellationToken
);
}
// check if content-length is > 0
if
(
request
.
ContentLength
>
0
)
// send body to server if available
if
(
request
.
HasBody
)
{
if
(
request
.
IsBodyRead
)
{
var
writer
=
args
.
HttpClient
.
Connection
.
StreamWriter
;
await
writer
.
WriteBodyAsync
(
body
,
request
.
IsChunked
,
cancellationToken
);
}
else
else
if
(!
request
.
ExpectationFailed
)
{
if
(!
request
.
ExpectationFailed
)
{
if
(
request
.
HasBody
)
{
HttpWriter
writer
=
args
.
HttpClient
.
Connection
.
StreamWriter
;
await
args
.
CopyRequestBodyAsync
(
writer
,
TransformationMode
.
None
,
cancellationToken
);
}
}
// get the request body unless an unsuccessful 100 continue request was made
HttpWriter
writer
=
args
.
HttpClient
.
Connection
.
StreamWriter
;
await
args
.
CopyRequestBodyAsync
(
writer
,
TransformationMode
.
None
,
cancellationToken
);
}
}
args
.
TimeLine
[
"Request Sent"
]
=
DateTime
.
Now
;
// If not expectation failed response was returned by server then parse response
if
(!
request
.
ExpectationFailed
)
{
await
handleHttpSessionResponse
(
args
);
}
// parse and send response
await
handleHttpSessionResponse
(
args
);
}
/// <summary>
...
...
src/Titanium.Web.Proxy/ResponseHandler.cs
View file @
9fcf5c3b
...
...
@@ -25,6 +25,14 @@ namespace Titanium.Web.Proxy
// read response & headers from server
await
args
.
HttpClient
.
ReceiveResponse
(
cancellationToken
);
// Server may send expect-continue even if not asked for it in request.
// According to spec "the client can simply discard this interim response."
if
(
args
.
HttpClient
.
Response
.
StatusCode
==
(
int
)
HttpStatusCode
.
Continue
)
{
await
args
.
ClearResponse
(
cancellationToken
);
await
args
.
HttpClient
.
ReceiveResponse
(
cancellationToken
);
}
args
.
TimeLine
[
"Response Received"
]
=
DateTime
.
Now
;
var
response
=
args
.
HttpClient
.
Response
;
...
...
@@ -92,20 +100,6 @@ namespace Titanium.Web.Proxy
response
.
Locked
=
true
;
// Write back to client 100-conitinue response if that's what server returned
if
(
response
.
Is100Continue
)
{
await
clientStreamWriter
.
WriteResponseStatusAsync
(
response
.
HttpVersion
,
(
int
)
HttpStatusCode
.
Continue
,
"Continue"
,
cancellationToken
);
await
clientStreamWriter
.
WriteLineAsync
(
cancellationToken
);
}
else
if
(
response
.
ExpectationFailed
)
{
await
clientStreamWriter
.
WriteResponseStatusAsync
(
response
.
HttpVersion
,
(
int
)
HttpStatusCode
.
ExpectationFailed
,
"Expectation Failed"
,
cancellationToken
);
await
clientStreamWriter
.
WriteLineAsync
(
cancellationToken
);
}
if
(!
args
.
IsTransparent
)
{
response
.
Headers
.
FixProxyHeaders
();
...
...
tests/Titanium.Web.Proxy.IntegrationTests/.editorconfig
0 → 100644
View file @
9fcf5c3b
# To learn more about .editorconfig see https://aka.ms/editorconfigdocs
###############################
# Core EditorConfig Options #
###############################
root = true
# All files
[*]
indent_style = space
# Code files
[*.{cs,csx,vb,vbx}]
indent_size = 4
insert_final_newline = true
charset = utf-8-bom
###############################
# .NET Coding Conventions #
###############################
[*.{cs,vb}]
# Organize usings
dotnet_sort_system_directives_first = true
# this. preferences
dotnet_style_qualification_for_field = false:silent
dotnet_style_qualification_for_property = false:silent
dotnet_style_qualification_for_method = false:silent
dotnet_style_qualification_for_event = false:silent
# Language keywords vs BCL types preferences
dotnet_style_predefined_type_for_locals_parameters_members = true:silent
dotnet_style_predefined_type_for_member_access = true:silent
# Parentheses preferences
dotnet_style_parentheses_in_arithmetic_binary_operators = always_for_clarity:silent
dotnet_style_parentheses_in_relational_binary_operators = always_for_clarity:silent
dotnet_style_parentheses_in_other_binary_operators = always_for_clarity:silent
dotnet_style_parentheses_in_other_operators = never_if_unnecessary:silent
# Modifier preferences
dotnet_style_require_accessibility_modifiers = for_non_interface_members:silent
dotnet_style_readonly_field = true:suggestion
# Expression-level preferences
dotnet_style_object_initializer = true:suggestion
dotnet_style_collection_initializer = true:suggestion
dotnet_style_explicit_tuple_names = true:suggestion
dotnet_style_null_propagation = true:suggestion
dotnet_style_coalesce_expression = true:suggestion
dotnet_style_prefer_is_null_check_over_reference_equality_method = true:silent
dotnet_prefer_inferred_tuple_names = true:suggestion
dotnet_prefer_inferred_anonymous_type_member_names = true:suggestion
dotnet_style_prefer_auto_properties = true:silent
dotnet_style_prefer_conditional_expression_over_assignment = true:silent
dotnet_style_prefer_conditional_expression_over_return = true:silent
###############################
# Naming Conventions #
###############################
# Style Definitions
dotnet_naming_style.pascal_case_style.capitalization = pascal_case
# Use PascalCase for constant fields
dotnet_naming_rule.constant_fields_should_be_pascal_case.severity = suggestion
dotnet_naming_rule.constant_fields_should_be_pascal_case.symbols = constant_fields
dotnet_naming_rule.constant_fields_should_be_pascal_case.style = pascal_case_style
dotnet_naming_symbols.constant_fields.applicable_kinds = field
dotnet_naming_symbols.constant_fields.applicable_accessibilities = *
dotnet_naming_symbols.constant_fields.required_modifiers = const
###############################
# C# Coding Conventions #
###############################
[*.cs]
# var preferences
csharp_style_var_for_built_in_types = true:silent
csharp_style_var_when_type_is_apparent = true:silent
csharp_style_var_elsewhere = true:silent
# Expression-bodied members
csharp_style_expression_bodied_methods = false:silent
csharp_style_expression_bodied_constructors = false:silent
csharp_style_expression_bodied_operators = false:silent
csharp_style_expression_bodied_properties = true:silent
csharp_style_expression_bodied_indexers = true:silent
csharp_style_expression_bodied_accessors = true:silent
# Pattern matching preferences
csharp_style_pattern_matching_over_is_with_cast_check = true:suggestion
csharp_style_pattern_matching_over_as_with_null_check = true:suggestion
# Null-checking preferences
csharp_style_throw_expression = true:suggestion
csharp_style_conditional_delegate_call = true:suggestion
# Modifier preferences
csharp_preferred_modifier_order = public,private,protected,internal,static,extern,new,virtual,abstract,sealed,override,readonly,unsafe,volatile,async:suggestion
# Expression-level preferences
csharp_prefer_braces = true:silent
csharp_style_deconstructed_variable_declaration = true:suggestion
csharp_prefer_simple_default_expression = true:suggestion
csharp_style_pattern_local_over_anonymous_function = true:suggestion
csharp_style_inlined_variable_declaration = true:suggestion
###############################
# C# Formatting Rules #
###############################
# New line preferences
csharp_new_line_before_open_brace = all
csharp_new_line_before_else = true
csharp_new_line_before_catch = true
csharp_new_line_before_finally = true
csharp_new_line_before_members_in_object_initializers = true
csharp_new_line_before_members_in_anonymous_types = true
csharp_new_line_between_query_expression_clauses = true
# Indentation preferences
csharp_indent_case_contents = true
csharp_indent_switch_labels = true
csharp_indent_labels = flush_left
# Space preferences
csharp_space_after_cast = false
csharp_space_after_keywords_in_control_flow_statements = true
csharp_space_between_method_call_parameter_list_parentheses = false
csharp_space_between_method_declaration_parameter_list_parentheses = false
csharp_space_between_parentheses = false
csharp_space_before_colon_in_inheritance_clause = true
csharp_space_after_colon_in_inheritance_clause = true
csharp_space_around_binary_operators = before_and_after
csharp_space_between_method_declaration_empty_parameter_list_parentheses = false
csharp_space_between_method_call_name_and_opening_parenthesis = false
csharp_space_between_method_call_empty_parameter_list_parentheses = false
# Wrapping preferences
csharp_preserve_single_line_statements = true
csharp_preserve_single_line_blocks = true
###############################
# VB Coding Conventions #
###############################
[*.vb]
# Modifier preferences
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
tests/Titanium.Web.Proxy.IntegrationTests/ExpectContinueTests.cs
0 → 100644
View file @
9fcf5c3b
using
Microsoft.AspNetCore.Http
;
using
Microsoft.VisualStudio.TestTools.UnitTesting
;
using
System
;
using
System.Buffers
;
using
System.Collections.Generic
;
using
System.IO
;
using
System.Linq
;
using
System.Net
;
using
System.Net.Http
;
using
System.Net.Sockets
;
using
System.Text
;
using
System.Threading.Tasks
;
using
Titanium.Web.Proxy.EventArguments
;
using
Titanium.Web.Proxy.Http
;
using
Titanium.Web.Proxy.IntegrationTests.Helpers
;
namespace
Titanium.Web.Proxy.IntegrationTests
{
[
TestClass
]
public
class
ExpectContinueTests
{
[
TestMethod
]
public
async
Task
ReverseProxy_GotContinueAndOkResponse
()
{
var
testSuite
=
new
TestSuite
();
var
server
=
testSuite
.
GetServer
();
var
continueServer
=
new
HttpContinueServer
()
{
ExpectationResponse
=
HttpStatusCode
.
Continue
,
ResponseBody
=
"I am server. I received your greetings."
};
server
.
HandleTcpRequest
(
continueServer
.
HandleRequest
);
var
proxy
=
testSuite
.
GetReverseProxy
();
proxy
.
Enable100ContinueBehaviour
=
true
;
proxy
.
BeforeRequest
+=
(
sender
,
e
)
=>
{
e
.
HttpClient
.
Request
.
RequestUri
=
new
Uri
(
server
.
ListeningTcpUrl
);
return
Task
.
CompletedTask
;
};
var
client
=
new
HttpContinueClient
();
var
response
=
await
client
.
Post
(
"localhost"
,
proxy
.
ProxyEndPoints
[
0
].
Port
,
"Hello server. I am a client."
);
Assert
.
IsNotNull
(
response
,
"No response to 'expect: 100-continue' request"
);
Assert
.
AreEqual
((
int
)
HttpStatusCode
.
OK
,
response
.
StatusCode
);
Assert
.
AreEqual
(
continueServer
.
ResponseBody
,
response
.
BodyString
);
}
[
TestMethod
]
public
async
Task
ReverseProxy_GotExpectationFailedResponse
()
{
var
testSuite
=
new
TestSuite
();
var
server
=
testSuite
.
GetServer
();
var
continueServer
=
new
HttpContinueServer
()
{
ExpectationResponse
=
HttpStatusCode
.
ExpectationFailed
};
server
.
HandleTcpRequest
(
continueServer
.
HandleRequest
);
var
proxy
=
testSuite
.
GetReverseProxy
();
proxy
.
Enable100ContinueBehaviour
=
true
;
proxy
.
BeforeRequest
+=
(
sender
,
e
)
=>
{
e
.
HttpClient
.
Request
.
RequestUri
=
new
Uri
(
server
.
ListeningTcpUrl
);
return
Task
.
CompletedTask
;
};
var
client
=
new
HttpContinueClient
();
var
response
=
await
client
.
Post
(
"localhost"
,
proxy
.
ProxyEndPoints
[
0
].
Port
,
"Hello server. I am a client."
);
Assert
.
IsNotNull
(
response
,
"No response to 'expect: 100-continue' request"
);
Assert
.
AreEqual
((
int
)
HttpStatusCode
.
ExpectationFailed
,
response
.
StatusCode
);
}
[
TestMethod
]
public
async
Task
ReverseProxy_GotNotFoundResponse
()
{
var
testSuite
=
new
TestSuite
();
var
server
=
testSuite
.
GetServer
();
var
continueServer
=
new
HttpContinueServer
()
{
ExpectationResponse
=
HttpStatusCode
.
NotFound
};
server
.
HandleTcpRequest
(
continueServer
.
HandleRequest
);
var
proxy
=
testSuite
.
GetReverseProxy
();
proxy
.
Enable100ContinueBehaviour
=
true
;
proxy
.
BeforeRequest
+=
(
sender
,
e
)
=>
{
e
.
HttpClient
.
Request
.
RequestUri
=
new
Uri
(
server
.
ListeningTcpUrl
);
return
Task
.
CompletedTask
;
};
var
client
=
new
HttpContinueClient
();
var
response
=
await
client
.
Post
(
"localhost"
,
proxy
.
ProxyEndPoints
[
0
].
Port
,
"Hello server. I am a client."
);
Assert
.
IsNotNull
(
response
,
"No response to 'expect: 100-continue' request"
);
Assert
.
AreEqual
((
int
)
HttpStatusCode
.
NotFound
,
response
.
StatusCode
);
}
[
TestMethod
]
public
async
Task
ReverseProxy_BeforeRequestThrows
()
{
var
testSuite
=
new
TestSuite
();
var
server
=
testSuite
.
GetServer
();
var
continueServer
=
new
HttpContinueServer
()
{
ExpectationResponse
=
HttpStatusCode
.
Continue
};
server
.
HandleTcpRequest
(
continueServer
.
HandleRequest
);
var
dbzEx
=
new
DivideByZeroException
(
"Undefined"
);
var
dbzString
=
$"
{
dbzEx
.
GetType
()}
:
{
dbzEx
.
Message
}
"
;
var
proxy
=
testSuite
.
GetReverseProxy
();
proxy
.
Enable100ContinueBehaviour
=
true
;
proxy
.
BeforeRequest
+=
(
sender
,
e
)
=>
{
try
{
e
.
HttpClient
.
Request
.
RequestUri
=
new
Uri
(
server
.
ListeningTcpUrl
);
throw
dbzEx
;
}
catch
{
var
serverError
=
new
Response
(
Encoding
.
ASCII
.
GetBytes
(
dbzString
))
{
HttpVersion
=
new
Version
(
1
,
1
),
StatusCode
=
(
int
)
HttpStatusCode
.
InternalServerError
,
StatusDescription
=
HttpStatusCode
.
InternalServerError
.
ToString
()
};
e
.
Respond
(
serverError
);
}
return
Task
.
CompletedTask
;
};
var
client
=
new
HttpContinueClient
();
var
response
=
await
client
.
Post
(
"localhost"
,
proxy
.
ProxyEndPoints
[
0
].
Port
,
"Hello server. I am a client."
);
Assert
.
IsNotNull
(
response
,
"No response to 'expect: 100-continue' request"
);
Assert
.
AreEqual
(
response
.
StatusCode
,
(
int
)
HttpStatusCode
.
InternalServerError
);
Assert
.
AreEqual
(
response
.
BodyString
,
dbzString
);
}
}
}
tests/Titanium.Web.Proxy.IntegrationTests/Helpers/HttpContinueClient.cs
0 → 100644
View file @
9fcf5c3b
using
System
;
using
System.Net.Sockets
;
using
System.Text
;
using
System.Threading.Tasks
;
using
Titanium.Web.Proxy.Helpers
;
using
Titanium.Web.Proxy.Http
;
namespace
Titanium.Web.Proxy.IntegrationTests.Helpers
{
class
HttpContinueClient
{
private
static
Encoding
MsgEncoding
=
HttpHelper
.
GetEncodingFromContentType
(
null
);
public
async
Task
<
Response
>
Post
(
string
server
,
int
port
,
string
content
)
{
var
message
=
MsgEncoding
.
GetBytes
(
content
);
var
client
=
new
TcpClient
(
server
,
port
);
client
.
SendTimeout
=
client
.
ReceiveTimeout
=
500
;
var
request
=
new
Request
{
Method
=
"POST"
,
OriginalUrl
=
"/"
,
HttpVersion
=
new
Version
(
1
,
1
)
};
request
.
Headers
.
AddHeader
(
KnownHeaders
.
Host
,
server
);
request
.
Headers
.
AddHeader
(
KnownHeaders
.
ContentLength
,
message
.
Length
.
ToString
());
request
.
Headers
.
AddHeader
(
KnownHeaders
.
Expect
,
KnownHeaders
.
Expect100Continue
);
var
header
=
MsgEncoding
.
GetBytes
(
request
.
HeaderText
);
await
client
.
GetStream
().
WriteAsync
(
header
,
0
,
header
.
Length
);
var
buffer
=
new
byte
[
1024
];
var
responseMsg
=
string
.
Empty
;
Response
response
=
null
;
while
((
response
=
HttpMessageParsing
.
ParseResponse
(
responseMsg
))
==
null
)
{
var
readTask
=
client
.
GetStream
().
ReadAsync
(
buffer
,
0
,
1024
);
if
(!
readTask
.
Wait
(
200
))
return
null
;
responseMsg
+=
MsgEncoding
.
GetString
(
buffer
,
0
,
readTask
.
Result
);
}
if
(
response
.
StatusCode
==
100
)
{
await
client
.
GetStream
().
WriteAsync
(
message
);
responseMsg
=
string
.
Empty
;
while
((
response
=
HttpMessageParsing
.
ParseResponse
(
responseMsg
))
==
null
)
{
var
readTask
=
client
.
GetStream
().
ReadAsync
(
buffer
,
0
,
1024
);
if
(!
readTask
.
Wait
(
200
))
return
null
;
responseMsg
+=
MsgEncoding
.
GetString
(
buffer
,
0
,
readTask
.
Result
);
}
return
response
;
}
else
{
return
response
;
}
}
}
}
tests/Titanium.Web.Proxy.IntegrationTests/Helpers/HttpContinueServer.cs
0 → 100644
View file @
9fcf5c3b
using
System
;
using
System.IO.Pipelines
;
using
System.Net
;
using
System.Text
;
using
System.Threading.Tasks
;
using
Microsoft.AspNetCore.Connections
;
using
Titanium.Web.Proxy.Helpers
;
using
Titanium.Web.Proxy.Http
;
namespace
Titanium.Web.Proxy.IntegrationTests.Helpers
{
class
HttpContinueServer
{
public
HttpStatusCode
ExpectationResponse
;
public
string
ResponseBody
;
private
static
Encoding
MsgEncoding
=
HttpHelper
.
GetEncodingFromContentType
(
null
);
public
async
Task
HandleRequest
(
ConnectionContext
context
)
{
var
request
=
await
ReadHeaders
(
context
.
Transport
.
Input
);
if
(
request
.
ExpectContinue
)
{
var
respondContinue
=
new
Response
{
HttpVersion
=
request
.
HttpVersion
,
StatusCode
=
(
int
)
ExpectationResponse
,
StatusDescription
=
ExpectationResponse
.
ToString
()
};
await
context
.
Transport
.
Output
.
WriteAsync
(
MsgEncoding
.
GetBytes
(
respondContinue
.
HeaderText
));
if
(
ExpectationResponse
!=
HttpStatusCode
.
Continue
)
return
;
}
request
=
await
ReadBody
(
request
,
context
.
Transport
.
Input
);
var
responseMsg
=
MsgEncoding
.
GetBytes
(
ResponseBody
);
var
respondOk
=
new
Response
(
responseMsg
)
{
HttpVersion
=
new
Version
(
1
,
1
),
StatusCode
=
(
int
)
HttpStatusCode
.
OK
,
StatusDescription
=
HttpStatusCode
.
OK
.
ToString
()
};
await
context
.
Transport
.
Output
.
WriteAsync
(
MsgEncoding
.
GetBytes
(
respondOk
.
HeaderText
));
await
context
.
Transport
.
Output
.
WriteAsync
(
responseMsg
);
context
.
Transport
.
Output
.
Complete
();
}
private
async
Task
<
Request
>
ReadHeaders
(
PipeReader
input
)
{
Request
request
=
null
;
try
{
var
requestMsg
=
string
.
Empty
;
while
((
request
=
HttpMessageParsing
.
ParseRequest
(
requestMsg
,
false
))
==
null
)
{
var
result
=
await
input
.
ReadAsync
();
foreach
(
var
seg
in
result
.
Buffer
)
requestMsg
+=
MsgEncoding
.
GetString
(
seg
.
Span
);
input
.
AdvanceTo
(
result
.
Buffer
.
End
);
}
}
catch
(
Exception
ex
)
{
Console
.
WriteLine
(
$"
{
ex
.
GetType
()}
:
{
ex
.
Message
}
"
);
}
return
request
;
}
private
async
Task
<
Request
>
ReadBody
(
Request
request
,
PipeReader
input
)
{
var
msg
=
request
.
HeaderText
;
try
{
while
((
request
=
HttpMessageParsing
.
ParseRequest
(
msg
,
true
))
==
null
)
{
var
result
=
await
input
.
ReadAsync
();
foreach
(
var
seg
in
result
.
Buffer
)
msg
+=
MsgEncoding
.
GetString
(
seg
.
Span
);
input
.
AdvanceTo
(
result
.
Buffer
.
End
);
}
}
catch
(
Exception
ex
)
{
Console
.
WriteLine
(
$"
{
ex
.
GetType
()}
:
{
ex
.
Message
}
"
);
}
return
request
;
}
}
}
tests/Titanium.Web.Proxy.IntegrationTests/Helpers/HttpMessageParsing.cs
0 → 100644
View file @
9fcf5c3b
using
System.IO
;
using
System.Text
;
using
Titanium.Web.Proxy.Http
;
using
Titanium.Web.Proxy.Shared
;
namespace
Titanium.Web.Proxy.IntegrationTests.Helpers
{
internal
static
class
HttpMessageParsing
{
/// <summary>
/// This is a terribly inefficient way of reading & parsing an
/// http request, but it's good enough for testing purposes.
/// </summary>
/// <param name="messageText">The request message</param>
/// <returns>Request object if message complete, null otherwise</returns>
internal
static
Request
ParseRequest
(
string
messageText
,
bool
requireBody
)
{
var
reader
=
new
StringReader
(
messageText
);
var
line
=
reader
.
ReadLine
();
if
(
string
.
IsNullOrEmpty
(
line
))
return
null
;
try
{
Request
.
ParseRequestLine
(
line
,
out
var
method
,
out
var
url
,
out
var
version
);
RequestResponseBase
request
=
new
Request
()
{
Method
=
method
,
OriginalUrl
=
url
,
HttpVersion
=
version
};
while
(!
string
.
IsNullOrEmpty
(
line
=
reader
.
ReadLine
()))
{
var
header
=
line
.
Split
(
ProxyConstants
.
ColonSplit
,
2
);
request
.
Headers
.
AddHeader
(
header
[
0
],
header
[
1
]);
}
// First zero-length line denotes end of headers. If we
// didn't get one, then we're not done with request
if
(
line
?.
Length
!=
0
)
return
null
;
if
(!
requireBody
)
return
request
as
Request
;
if
(
ParseBody
(
reader
,
ref
request
))
return
request
as
Request
;
}
catch
{
}
return
null
;
}
/// <summary>
/// This is a terribly inefficient way of reading & parsing an
/// http response, but it's good enough for testing purposes.
/// </summary>
/// <param name="messageText">The response message</param>
/// <returns>Response object if message complete, null otherwise</returns>
internal
static
Response
ParseResponse
(
string
messageText
)
{
var
reader
=
new
StringReader
(
messageText
);
var
line
=
reader
.
ReadLine
();
if
(
string
.
IsNullOrEmpty
(
line
))
return
null
;
try
{
Response
.
ParseResponseLine
(
line
,
out
var
version
,
out
var
status
,
out
var
desc
);
RequestResponseBase
response
=
new
Response
()
{
HttpVersion
=
version
,
StatusCode
=
status
,
StatusDescription
=
desc
};
while
(!
string
.
IsNullOrEmpty
(
line
=
reader
.
ReadLine
()))
{
var
header
=
line
.
Split
(
ProxyConstants
.
ColonSplit
,
2
);
response
.
Headers
.
AddHeader
(
header
[
0
],
header
[
1
]);
}
// First zero-length line denotes end of headers. If we
// didn't get one, then we're not done with response
if
(
line
?.
Length
!=
0
)
return
null
;
if
(
ParseBody
(
reader
,
ref
response
))
return
response
as
Response
;
}
catch
{
}
return
null
;
}
private
static
bool
ParseBody
(
StringReader
reader
,
ref
RequestResponseBase
obj
)
{
obj
.
OriginalContentLength
=
obj
.
ContentLength
;
if
(
obj
.
ContentLength
<=
0
)
{
// no body, done
return
true
;
}
else
{
obj
.
Body
=
Encoding
.
ASCII
.
GetBytes
(
reader
.
ReadToEnd
());
if
(
obj
.
ContentLength
==
obj
.
OriginalContentLength
)
return
true
;
// done reading body
else
return
false
;
// not done reading body
}
}
}
}
tests/Titanium.Web.Proxy.IntegrationTests/Setup/TestServer.cs
View file @
9fcf5c3b
using
Microsoft.AspNetCore
;
using
Microsoft.AspNetCore.Builder
;
using
Microsoft.AspNetCore.Connections
;
using
Microsoft.AspNetCore.Hosting
;
using
Microsoft.AspNetCore.Hosting.Server.Features
;
using
Microsoft.AspNetCore.Http
;
using
System
;
using
Microsoft.Extensions.DependencyInjection
;
using
System
;
using
System.Linq
;
using
System.Net
;
using
System.Security.Cryptography.X509Certificates
;
using
System.Text
;
using
System.Threading.Tasks
;
namespace
Titanium.Web.Proxy.IntegrationTests.Setup
...
...
@@ -18,9 +18,11 @@ namespace Titanium.Web.Proxy.IntegrationTests.Setup
{
public
string
ListeningHttpUrl
=>
$"http://localhost:
{
HttpListeningPort
}
"
;
public
string
ListeningHttpsUrl
=>
$"https://localhost:
{
HttpsListeningPort
}
"
;
public
string
ListeningTcpUrl
=>
$"http://localhost:
{
TcpListeningPort
}
"
;
public
int
HttpListeningPort
{
get
;
private
set
;
}
public
int
HttpsListeningPort
{
get
;
private
set
;
}
public
int
TcpListeningPort
{
get
;
private
set
;
}
private
IWebHost
host
;
public
TestServer
(
X509Certificate2
serverCertificate
)
...
...
@@ -39,6 +41,18 @@ namespace Titanium.Web.Proxy.IntegrationTests.Setup
{
listenOptions
.
UseHttps
(
serverCertificate
);
});
options
.
Listen
(
IPAddress
.
Loopback
,
0
,
listenOptions
=>
{
listenOptions
.
Run
(
context
=>
{
if
(
tcpRequestHandler
==
null
)
{
throw
new
Exception
(
"Test server not configured to handle tcp request."
);
}
return
tcpRequestHandler
(
context
);
});
});
})
.
Build
();
...
...
@@ -53,14 +67,24 @@ namespace Titanium.Web.Proxy.IntegrationTests.Setup
string
httpsAddress
=
addresses
[
1
];
HttpsListeningPort
=
int
.
Parse
(
httpsAddress
.
Split
(
':'
)[
2
]);
string
tcpAddress
=
addresses
[
2
];
TcpListeningPort
=
int
.
Parse
(
tcpAddress
.
Split
(
':'
)[
2
]);
}
Func
<
HttpContext
,
Task
>
requestHandler
=
null
;
Func
<
ConnectionContext
,
Task
>
tcpRequestHandler
=
null
;
public
void
HandleRequest
(
Func
<
HttpContext
,
Task
>
requestHandler
)
{
this
.
requestHandler
=
requestHandler
;
}
public
void
HandleTcpRequest
(
Func
<
ConnectionContext
,
Task
>
tcpRequestHandler
)
{
this
.
tcpRequestHandler
=
tcpRequestHandler
;
}
public
void
Dispose
()
{
host
.
StopAsync
().
Wait
();
...
...
tests/Titanium.Web.Proxy.IntegrationTests/StrongNameKey.snk
0 → 100644
View file @
9fcf5c3b
File added
tests/Titanium.Web.Proxy.IntegrationTests/Titanium.Web.Proxy.IntegrationTests.csproj
View file @
9fcf5c3b
...
...
@@ -2,6 +2,8 @@
<PropertyGroup>
<TargetFramework>netcoreapp2.2</TargetFramework>
<AssemblyOriginatorKeyFile>StrongNameKey.snk</AssemblyOriginatorKeyFile>
<SignAssembly>true</SignAssembly>
</PropertyGroup>
<ItemGroup>
...
...
tests/Titanium.Web.Proxy.IntegrationTests/Titanium.Web.Proxy.IntegrationTests.csproj.bak
0 → 100644
View file @
9fcf5c3b
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>netcoreapp2.2</TargetFramework>
</PropertyGroup>
<ItemGroup>
<None Include="..\..\.build\lib\rootCert.pfx" Link="rootCert.pfx">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>
</ItemGroup>
<ItemGroup>
<PackageReference Include="Microsoft.AspNetCore.App" />
<PackageReference Include="Microsoft.AspNetCore.Server.Kestrel" Version="2.2.0" />
<PackageReference Include="Microsoft.AspNetCore.Server.Kestrel.Https" Version="2.2.0" />
<PackageReference Include="Microsoft.Extensions.DependencyInjection.Abstractions" Version="2.2.0" />
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="15.9.0" />
<PackageReference Include="MSTest.TestAdapter" Version="1.4.0" />
<PackageReference Include="MSTest.TestFramework" Version="1.4.0" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\..\src\Titanium.Web.Proxy\Titanium.Web.Proxy.csproj" />
</ItemGroup>
</Project>
tests/Titanium.Web.Proxy.IntegrationTests/Titanium.Web.Proxy.IntegrationTests.sln
0 → 100644
View file @
9fcf5c3b
Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio 15
VisualStudioVersion = 15.0.28307.136
MinimumVisualStudioVersion = 10.0.40219.1
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Titanium.Web.Proxy.IntegrationTests", "Titanium.Web.Proxy.IntegrationTests.csproj", "{BE0BC910-468F-4F1A-AC3D-F0EC2C75108E}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Titanium.Web.Proxy", "..\..\src\Titanium.Web.Proxy\Titanium.Web.Proxy.csproj", "{F407A98E-290D-4A29-9451-22A6AE380586}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
Debug|x64 = Debug|x64
Release|Any CPU = Release|Any CPU
Release|x64 = Release|x64
EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution
{BE0BC910-468F-4F1A-AC3D-F0EC2C75108E}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{BE0BC910-468F-4F1A-AC3D-F0EC2C75108E}.Debug|Any CPU.Build.0 = Debug|Any CPU
{BE0BC910-468F-4F1A-AC3D-F0EC2C75108E}.Debug|x64.ActiveCfg = Debug|Any CPU
{BE0BC910-468F-4F1A-AC3D-F0EC2C75108E}.Debug|x64.Build.0 = Debug|Any CPU
{BE0BC910-468F-4F1A-AC3D-F0EC2C75108E}.Release|Any CPU.ActiveCfg = Release|Any CPU
{BE0BC910-468F-4F1A-AC3D-F0EC2C75108E}.Release|Any CPU.Build.0 = Release|Any CPU
{BE0BC910-468F-4F1A-AC3D-F0EC2C75108E}.Release|x64.ActiveCfg = Release|Any CPU
{BE0BC910-468F-4F1A-AC3D-F0EC2C75108E}.Release|x64.Build.0 = Release|Any CPU
{F407A98E-290D-4A29-9451-22A6AE380586}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{F407A98E-290D-4A29-9451-22A6AE380586}.Debug|Any CPU.Build.0 = Debug|Any CPU
{F407A98E-290D-4A29-9451-22A6AE380586}.Debug|x64.ActiveCfg = Debug|x64
{F407A98E-290D-4A29-9451-22A6AE380586}.Debug|x64.Build.0 = Debug|x64
{F407A98E-290D-4A29-9451-22A6AE380586}.Release|Any CPU.ActiveCfg = Release|Any CPU
{F407A98E-290D-4A29-9451-22A6AE380586}.Release|Any CPU.Build.0 = Release|Any CPU
{F407A98E-290D-4A29-9451-22A6AE380586}.Release|x64.ActiveCfg = Release|x64
{F407A98E-290D-4A29-9451-22A6AE380586}.Release|x64.Build.0 = Release|x64
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {B518E259-A504-4396-8138-8BFF322FAC80}
EndGlobalSection
EndGlobal
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment