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
1cc485fa
Commit
1cc485fa
authored
Jul 20, 2019
by
Honfika
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
remove redundant type specification
parent
3940b26d
Show whitespace changes
Inline
Side-by-side
Showing
5 changed files
with
28 additions
and
28 deletions
+28
-28
HttpHelper.cs
src/Titanium.Web.Proxy/Helpers/HttpHelper.cs
+3
-3
CopyStream.cs
src/Titanium.Web.Proxy/StreamExtended/Network/CopyStream.cs
+6
-6
CustomBufferedStream.cs
....Web.Proxy/StreamExtended/Network/CustomBufferedStream.cs
+11
-11
ICustomStreamReader.cs
...m.Web.Proxy/StreamExtended/Network/ICustomStreamReader.cs
+6
-6
SslTools.cs
src/Titanium.Web.Proxy/StreamExtended/SslTools.cs
+2
-2
No files found.
src/Titanium.Web.Proxy/Helpers/HttpHelper.cs
View file @
1cc485fa
...
@@ -123,7 +123,7 @@ namespace Titanium.Web.Proxy.Helpers
...
@@ -123,7 +123,7 @@ namespace Titanium.Web.Proxy.Helpers
/// </summary>
/// </summary>
/// <param name="clientStreamReader">The client stream reader.</param>
/// <param name="clientStreamReader">The client stream reader.</param>
/// <returns>1: when CONNECT, 0: when valid HTTP method, -1: otherwise</returns>
/// <returns>1: when CONNECT, 0: when valid HTTP method, -1: otherwise</returns>
internal
static
Task
<
int
>
IsConnectMethod
(
ICustomStreamReader
clientStreamReader
,
IBufferPool
bufferPool
,
int
bufferSize
,
CancellationToken
cancellationToken
=
default
(
CancellationToken
)
)
internal
static
Task
<
int
>
IsConnectMethod
(
ICustomStreamReader
clientStreamReader
,
IBufferPool
bufferPool
,
int
bufferSize
,
CancellationToken
cancellationToken
=
default
)
{
{
return
startsWith
(
clientStreamReader
,
bufferPool
,
bufferSize
,
"CONNECT"
,
cancellationToken
);
return
startsWith
(
clientStreamReader
,
bufferPool
,
bufferSize
,
"CONNECT"
,
cancellationToken
);
}
}
...
@@ -133,7 +133,7 @@ namespace Titanium.Web.Proxy.Helpers
...
@@ -133,7 +133,7 @@ namespace Titanium.Web.Proxy.Helpers
/// </summary>
/// </summary>
/// <param name="clientStreamReader">The client stream reader.</param>
/// <param name="clientStreamReader">The client stream reader.</param>
/// <returns>1: when PRI, 0: when valid HTTP method, -1: otherwise</returns>
/// <returns>1: when PRI, 0: when valid HTTP method, -1: otherwise</returns>
internal
static
Task
<
int
>
IsPriMethod
(
ICustomStreamReader
clientStreamReader
,
IBufferPool
bufferPool
,
int
bufferSize
,
CancellationToken
cancellationToken
=
default
(
CancellationToken
)
)
internal
static
Task
<
int
>
IsPriMethod
(
ICustomStreamReader
clientStreamReader
,
IBufferPool
bufferPool
,
int
bufferSize
,
CancellationToken
cancellationToken
=
default
)
{
{
return
startsWith
(
clientStreamReader
,
bufferPool
,
bufferSize
,
"PRI"
,
cancellationToken
);
return
startsWith
(
clientStreamReader
,
bufferPool
,
bufferSize
,
"PRI"
,
cancellationToken
);
}
}
...
@@ -146,7 +146,7 @@ namespace Titanium.Web.Proxy.Helpers
...
@@ -146,7 +146,7 @@ namespace Titanium.Web.Proxy.Helpers
/// <returns>
/// <returns>
/// 1: when starts with the given string, 0: when valid HTTP method, -1: otherwise
/// 1: when starts with the given string, 0: when valid HTTP method, -1: otherwise
/// </returns>
/// </returns>
private
static
async
Task
<
int
>
startsWith
(
ICustomStreamReader
clientStreamReader
,
IBufferPool
bufferPool
,
int
bufferSize
,
string
expectedStart
,
CancellationToken
cancellationToken
=
default
(
CancellationToken
)
)
private
static
async
Task
<
int
>
startsWith
(
ICustomStreamReader
clientStreamReader
,
IBufferPool
bufferPool
,
int
bufferSize
,
string
expectedStart
,
CancellationToken
cancellationToken
=
default
)
{
{
int
iRet
=
-
1
;
int
iRet
=
-
1
;
const
int
lengthToCheck
=
10
;
const
int
lengthToCheck
=
10
;
...
...
src/Titanium.Web.Proxy/StreamExtended/Network/CopyStream.cs
View file @
1cc485fa
...
@@ -40,7 +40,7 @@ namespace Titanium.Web.Proxy.StreamExtended.Network
...
@@ -40,7 +40,7 @@ namespace Titanium.Web.Proxy.StreamExtended.Network
this
.
bufferPool
=
bufferPool
;
this
.
bufferPool
=
bufferPool
;
}
}
public
async
Task
<
bool
>
FillBufferAsync
(
CancellationToken
cancellationToken
=
default
(
CancellationToken
)
)
public
async
Task
<
bool
>
FillBufferAsync
(
CancellationToken
cancellationToken
=
default
)
{
{
await
FlushAsync
(
cancellationToken
);
await
FlushAsync
(
cancellationToken
);
return
await
reader
.
FillBufferAsync
(
cancellationToken
);
return
await
reader
.
FillBufferAsync
(
cancellationToken
);
...
@@ -51,12 +51,12 @@ namespace Titanium.Web.Proxy.StreamExtended.Network
...
@@ -51,12 +51,12 @@ namespace Titanium.Web.Proxy.StreamExtended.Network
return
reader
.
PeekByteFromBuffer
(
index
);
return
reader
.
PeekByteFromBuffer
(
index
);
}
}
public
Task
<
int
>
PeekByteAsync
(
int
index
,
CancellationToken
cancellationToken
=
default
(
CancellationToken
)
)
public
Task
<
int
>
PeekByteAsync
(
int
index
,
CancellationToken
cancellationToken
=
default
)
{
{
return
reader
.
PeekByteAsync
(
index
,
cancellationToken
);
return
reader
.
PeekByteAsync
(
index
,
cancellationToken
);
}
}
public
Task
<
int
>
PeekBytesAsync
(
byte
[]
buffer
,
int
offset
,
int
index
,
int
size
,
CancellationToken
cancellationToken
=
default
(
CancellationToken
)
)
public
Task
<
int
>
PeekBytesAsync
(
byte
[]
buffer
,
int
offset
,
int
index
,
int
size
,
CancellationToken
cancellationToken
=
default
)
{
{
return
reader
.
PeekBytesAsync
(
buffer
,
offset
,
index
,
size
,
cancellationToken
);
return
reader
.
PeekBytesAsync
(
buffer
,
offset
,
index
,
size
,
cancellationToken
);
}
}
...
@@ -71,7 +71,7 @@ namespace Titanium.Web.Proxy.StreamExtended.Network
...
@@ -71,7 +71,7 @@ namespace Titanium.Web.Proxy.StreamExtended.Network
}
}
}
}
public
async
Task
FlushAsync
(
CancellationToken
cancellationToken
=
default
(
CancellationToken
)
)
public
async
Task
FlushAsync
(
CancellationToken
cancellationToken
=
default
)
{
{
//send out the current data from from the buffer
//send out the current data from from the buffer
if
(
bufferLength
>
0
)
if
(
bufferLength
>
0
)
...
@@ -108,7 +108,7 @@ namespace Titanium.Web.Proxy.StreamExtended.Network
...
@@ -108,7 +108,7 @@ namespace Titanium.Web.Proxy.StreamExtended.Network
return
result
;
return
result
;
}
}
public
async
Task
<
int
>
ReadAsync
(
byte
[]
buffer
,
int
offset
,
int
count
,
CancellationToken
cancellationToken
=
default
(
CancellationToken
)
)
public
async
Task
<
int
>
ReadAsync
(
byte
[]
buffer
,
int
offset
,
int
count
,
CancellationToken
cancellationToken
=
default
)
{
{
int
result
=
await
reader
.
ReadAsync
(
buffer
,
offset
,
count
,
cancellationToken
);
int
result
=
await
reader
.
ReadAsync
(
buffer
,
offset
,
count
,
cancellationToken
);
if
(
result
>
0
)
if
(
result
>
0
)
...
@@ -127,7 +127,7 @@ namespace Titanium.Web.Proxy.StreamExtended.Network
...
@@ -127,7 +127,7 @@ namespace Titanium.Web.Proxy.StreamExtended.Network
return
result
;
return
result
;
}
}
public
Task
<
string
>
ReadLineAsync
(
CancellationToken
cancellationToken
=
default
(
CancellationToken
)
)
public
Task
<
string
>
ReadLineAsync
(
CancellationToken
cancellationToken
=
default
)
{
{
return
CustomBufferedStream
.
ReadLineInternalAsync
(
this
,
bufferPool
,
cancellationToken
);
return
CustomBufferedStream
.
ReadLineInternalAsync
(
this
,
bufferPool
,
cancellationToken
);
}
}
...
...
src/Titanium.Web.Proxy/StreamExtended/Network/CustomBufferedStream.cs
View file @
1cc485fa
...
@@ -138,7 +138,7 @@ namespace Titanium.Web.Proxy.StreamExtended.Network
...
@@ -138,7 +138,7 @@ namespace Titanium.Web.Proxy.StreamExtended.Network
/// <returns>
/// <returns>
/// A task that represents the asynchronous copy operation.
/// A task that represents the asynchronous copy operation.
/// </returns>
/// </returns>
public
override
async
Task
CopyToAsync
(
Stream
destination
,
int
bufferSize
,
CancellationToken
cancellationToken
=
default
(
CancellationToken
)
)
public
override
async
Task
CopyToAsync
(
Stream
destination
,
int
bufferSize
,
CancellationToken
cancellationToken
=
default
)
{
{
if
(
bufferLength
>
0
)
if
(
bufferLength
>
0
)
{
{
...
@@ -157,7 +157,7 @@ namespace Titanium.Web.Proxy.StreamExtended.Network
...
@@ -157,7 +157,7 @@ namespace Titanium.Web.Proxy.StreamExtended.Network
/// <returns>
/// <returns>
/// A task that represents the asynchronous flush operation.
/// A task that represents the asynchronous flush operation.
/// </returns>
/// </returns>
public
override
Task
FlushAsync
(
CancellationToken
cancellationToken
=
default
(
CancellationToken
)
)
public
override
Task
FlushAsync
(
CancellationToken
cancellationToken
=
default
)
{
{
return
baseStream
.
FlushAsync
(
cancellationToken
);
return
baseStream
.
FlushAsync
(
cancellationToken
);
}
}
...
@@ -182,7 +182,7 @@ namespace Titanium.Web.Proxy.StreamExtended.Network
...
@@ -182,7 +182,7 @@ namespace Titanium.Web.Proxy.StreamExtended.Network
/// less than the requested number, or it can be 0 (zero)
/// less than the requested number, or it can be 0 (zero)
/// if the end of the stream has been reached.
/// if the end of the stream has been reached.
/// </returns>
/// </returns>
public
override
async
Task
<
int
>
ReadAsync
(
byte
[]
buffer
,
int
offset
,
int
count
,
CancellationToken
cancellationToken
=
default
(
CancellationToken
)
)
public
override
async
Task
<
int
>
ReadAsync
(
byte
[]
buffer
,
int
offset
,
int
count
,
CancellationToken
cancellationToken
=
default
)
{
{
if
(
bufferLength
==
0
)
if
(
bufferLength
==
0
)
{
{
...
@@ -228,7 +228,7 @@ namespace Titanium.Web.Proxy.StreamExtended.Network
...
@@ -228,7 +228,7 @@ namespace Titanium.Web.Proxy.StreamExtended.Network
/// <param name="index">The index.</param>
/// <param name="index">The index.</param>
/// <param name="cancellationToken">The cancellation token.</param>
/// <param name="cancellationToken">The cancellation token.</param>
/// <returns></returns>
/// <returns></returns>
public
async
Task
<
int
>
PeekByteAsync
(
int
index
,
CancellationToken
cancellationToken
=
default
(
CancellationToken
)
)
public
async
Task
<
int
>
PeekByteAsync
(
int
index
,
CancellationToken
cancellationToken
=
default
)
{
{
if
(
Available
<=
index
)
if
(
Available
<=
index
)
{
{
...
@@ -258,7 +258,7 @@ namespace Titanium.Web.Proxy.StreamExtended.Network
...
@@ -258,7 +258,7 @@ namespace Titanium.Web.Proxy.StreamExtended.Network
/// <param name="index">The index.</param>
/// <param name="index">The index.</param>
/// <param name="cancellationToken">The cancellation token.</param>
/// <param name="cancellationToken">The cancellation token.</param>
/// <returns></returns>
/// <returns></returns>
public
async
Task
<
int
>
PeekBytesAsync
(
byte
[]
buffer
,
int
offset
,
int
index
,
int
size
,
CancellationToken
cancellationToken
=
default
(
CancellationToken
)
)
public
async
Task
<
int
>
PeekBytesAsync
(
byte
[]
buffer
,
int
offset
,
int
index
,
int
size
,
CancellationToken
cancellationToken
=
default
)
{
{
if
(
Available
<=
index
)
if
(
Available
<=
index
)
{
{
...
@@ -324,7 +324,7 @@ namespace Titanium.Web.Proxy.StreamExtended.Network
...
@@ -324,7 +324,7 @@ namespace Titanium.Web.Proxy.StreamExtended.Network
/// A task that represents the asynchronous write operation.
/// A task that represents the asynchronous write operation.
/// </returns>
/// </returns>
[
DebuggerStepThrough
]
[
DebuggerStepThrough
]
public
override
async
Task
WriteAsync
(
byte
[]
buffer
,
int
offset
,
int
count
,
CancellationToken
cancellationToken
=
default
(
CancellationToken
)
)
public
override
async
Task
WriteAsync
(
byte
[]
buffer
,
int
offset
,
int
count
,
CancellationToken
cancellationToken
=
default
)
{
{
OnDataWrite
(
buffer
,
offset
,
count
);
OnDataWrite
(
buffer
,
offset
,
count
);
...
@@ -484,7 +484,7 @@ namespace Titanium.Web.Proxy.StreamExtended.Network
...
@@ -484,7 +484,7 @@ namespace Titanium.Web.Proxy.StreamExtended.Network
/// </summary>
/// </summary>
/// <param name="cancellationToken">The cancellation token.</param>
/// <param name="cancellationToken">The cancellation token.</param>
/// <returns></returns>
/// <returns></returns>
public
async
Task
<
bool
>
FillBufferAsync
(
CancellationToken
cancellationToken
=
default
(
CancellationToken
)
)
public
async
Task
<
bool
>
FillBufferAsync
(
CancellationToken
cancellationToken
=
default
)
{
{
if
(
closed
)
if
(
closed
)
{
{
...
@@ -526,7 +526,7 @@ namespace Titanium.Web.Proxy.StreamExtended.Network
...
@@ -526,7 +526,7 @@ namespace Titanium.Web.Proxy.StreamExtended.Network
/// Read a line from the byte stream
/// Read a line from the byte stream
/// </summary>
/// </summary>
/// <returns></returns>
/// <returns></returns>
public
Task
<
string
>
ReadLineAsync
(
CancellationToken
cancellationToken
=
default
(
CancellationToken
)
)
public
Task
<
string
>
ReadLineAsync
(
CancellationToken
cancellationToken
=
default
)
{
{
return
ReadLineInternalAsync
(
this
,
bufferPool
,
cancellationToken
);
return
ReadLineInternalAsync
(
this
,
bufferPool
,
cancellationToken
);
}
}
...
@@ -535,9 +535,9 @@ namespace Titanium.Web.Proxy.StreamExtended.Network
...
@@ -535,9 +535,9 @@ namespace Titanium.Web.Proxy.StreamExtended.Network
/// Read a line from the byte stream
/// Read a line from the byte stream
/// </summary>
/// </summary>
/// <returns></returns>
/// <returns></returns>
internal
static
async
Task
<
string
>
ReadLineInternalAsync
(
ICustomStreamReader
reader
,
IBufferPool
bufferPool
,
CancellationToken
cancellationToken
=
default
(
CancellationToken
)
)
internal
static
async
Task
<
string
>
ReadLineInternalAsync
(
ICustomStreamReader
reader
,
IBufferPool
bufferPool
,
CancellationToken
cancellationToken
=
default
)
{
{
byte
lastChar
=
default
(
byte
)
;
byte
lastChar
=
default
;
int
bufferDataLength
=
0
;
int
bufferDataLength
=
0
;
...
@@ -591,7 +591,7 @@ namespace Titanium.Web.Proxy.StreamExtended.Network
...
@@ -591,7 +591,7 @@ namespace Titanium.Web.Proxy.StreamExtended.Network
/// Read until the last new line, ignores the result
/// Read until the last new line, ignores the result
/// </summary>
/// </summary>
/// <returns></returns>
/// <returns></returns>
public
async
Task
ReadAndIgnoreAllLinesAsync
(
CancellationToken
cancellationToken
=
default
(
CancellationToken
)
)
public
async
Task
ReadAndIgnoreAllLinesAsync
(
CancellationToken
cancellationToken
=
default
)
{
{
while
(!
string
.
IsNullOrEmpty
(
await
ReadLineAsync
(
cancellationToken
)))
while
(!
string
.
IsNullOrEmpty
(
await
ReadLineAsync
(
cancellationToken
)))
{
{
...
...
src/Titanium.Web.Proxy/StreamExtended/Network/ICustomStreamReader.cs
View file @
1cc485fa
...
@@ -19,7 +19,7 @@ namespace Titanium.Web.Proxy.StreamExtended.Network
...
@@ -19,7 +19,7 @@ namespace Titanium.Web.Proxy.StreamExtended.Network
/// Fills the buffer asynchronous.
/// Fills the buffer asynchronous.
/// </summary>
/// </summary>
/// <returns></returns>
/// <returns></returns>
Task
<
bool
>
FillBufferAsync
(
CancellationToken
cancellationToken
=
default
(
CancellationToken
)
);
Task
<
bool
>
FillBufferAsync
(
CancellationToken
cancellationToken
=
default
);
/// <summary>
/// <summary>
/// Peeks a byte from buffer.
/// Peeks a byte from buffer.
...
@@ -35,7 +35,7 @@ namespace Titanium.Web.Proxy.StreamExtended.Network
...
@@ -35,7 +35,7 @@ namespace Titanium.Web.Proxy.StreamExtended.Network
/// <param name="index">The index.</param>
/// <param name="index">The index.</param>
/// <param name="cancellationToken">The cancellation token.</param>
/// <param name="cancellationToken">The cancellation token.</param>
/// <returns></returns>
/// <returns></returns>
Task
<
int
>
PeekByteAsync
(
int
index
,
CancellationToken
cancellationToken
=
default
(
CancellationToken
)
);
Task
<
int
>
PeekByteAsync
(
int
index
,
CancellationToken
cancellationToken
=
default
);
/// <summary>
/// <summary>
/// Peeks bytes asynchronous.
/// Peeks bytes asynchronous.
...
@@ -45,7 +45,7 @@ namespace Titanium.Web.Proxy.StreamExtended.Network
...
@@ -45,7 +45,7 @@ namespace Titanium.Web.Proxy.StreamExtended.Network
/// <param name="index">The index.</param>
/// <param name="index">The index.</param>
/// <param name="cancellationToken">The cancellation token.</param>
/// <param name="cancellationToken">The cancellation token.</param>
/// <returns></returns>
/// <returns></returns>
Task
<
int
>
PeekBytesAsync
(
byte
[]
buffer
,
int
offset
,
int
index
,
int
size
,
CancellationToken
cancellationToken
=
default
(
CancellationToken
)
);
Task
<
int
>
PeekBytesAsync
(
byte
[]
buffer
,
int
offset
,
int
index
,
int
size
,
CancellationToken
cancellationToken
=
default
);
byte
ReadByteFromBuffer
();
byte
ReadByteFromBuffer
();
...
@@ -69,12 +69,12 @@ namespace Titanium.Web.Proxy.StreamExtended.Network
...
@@ -69,12 +69,12 @@ namespace Titanium.Web.Proxy.StreamExtended.Network
/// <param name="cancellationToken"></param>
/// <param name="cancellationToken"></param>
/// <returns>The number of bytes read</returns>
/// <returns>The number of bytes read</returns>
Task
<
int
>
ReadAsync
(
byte
[]
buffer
,
int
offset
,
int
bytesToRead
,
Task
<
int
>
ReadAsync
(
byte
[]
buffer
,
int
offset
,
int
bytesToRead
,
CancellationToken
cancellationToken
=
default
(
CancellationToken
)
);
CancellationToken
cancellationToken
=
default
);
/// <summary>
/// <summary>
/// Read a line from the byte stream
/// Read a line from the byte stream
/// </summary>
/// </summary>
/// <returns></returns>
/// <returns></returns>
Task
<
string
>
ReadLineAsync
(
CancellationToken
cancellationToken
=
default
(
CancellationToken
)
);
Task
<
string
>
ReadLineAsync
(
CancellationToken
cancellationToken
=
default
);
}
}
}
}
src/Titanium.Web.Proxy/StreamExtended/SslTools.cs
View file @
1cc485fa
...
@@ -32,7 +32,7 @@ namespace Titanium.Web.Proxy.StreamExtended
...
@@ -32,7 +32,7 @@ namespace Titanium.Web.Proxy.StreamExtended
/// <param name="bufferPool"></param>
/// <param name="bufferPool"></param>
/// <param name="cancellationToken"></param>
/// <param name="cancellationToken"></param>
/// <returns></returns>
/// <returns></returns>
public
static
async
Task
<
ClientHelloInfo
>
PeekClientHello
(
CustomBufferedStream
clientStream
,
IBufferPool
bufferPool
,
CancellationToken
cancellationToken
=
default
(
CancellationToken
)
)
public
static
async
Task
<
ClientHelloInfo
>
PeekClientHello
(
CustomBufferedStream
clientStream
,
IBufferPool
bufferPool
,
CancellationToken
cancellationToken
=
default
)
{
{
//detects the HTTPS ClientHello message as it is described in the following url:
//detects the HTTPS ClientHello message as it is described in the following url:
//https://stackoverflow.com/questions/3897883/how-to-detect-an-incoming-ssl-https-handshake-ssl-wire-format
//https://stackoverflow.com/questions/3897883/how-to-detect-an-incoming-ssl-https-handshake-ssl-wire-format
...
@@ -218,7 +218,7 @@ namespace Titanium.Web.Proxy.StreamExtended
...
@@ -218,7 +218,7 @@ namespace Titanium.Web.Proxy.StreamExtended
/// <param name="bufferPool"></param>
/// <param name="bufferPool"></param>
/// <param name="cancellationToken"></param>
/// <param name="cancellationToken"></param>
/// <returns></returns>
/// <returns></returns>
public
static
async
Task
<
ServerHelloInfo
>
PeekServerHello
(
CustomBufferedStream
serverStream
,
IBufferPool
bufferPool
,
CancellationToken
cancellationToken
=
default
(
CancellationToken
)
)
public
static
async
Task
<
ServerHelloInfo
>
PeekServerHello
(
CustomBufferedStream
serverStream
,
IBufferPool
bufferPool
,
CancellationToken
cancellationToken
=
default
)
{
{
//detects the HTTPS ClientHello message as it is described in the following url:
//detects the HTTPS ClientHello message as it is described in the following url:
//https://stackoverflow.com/questions/3897883/how-to-detect-an-incoming-ssl-https-handshake-ssl-wire-format
//https://stackoverflow.com/questions/3897883/how-to-detect-an-incoming-ssl-https-handshake-ssl-wire-format
...
...
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