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
ffe306c2
Commit
ffe306c2
authored
Jan 04, 2016
by
titanium007
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Separate request & response
parent
f69bed23
Expand all
Hide whitespace changes
Inline
Side-by-side
Showing
6 changed files
with
201 additions
and
202 deletions
+201
-202
ProxyTestController.cs
Titanium.Web.Proxy.Test/ProxyTestController.cs
+1
-1
SessionEventArgs.cs
Titanium.Web.Proxy/EventArguments/SessionEventArgs.cs
+76
-87
HttpWebClient.cs
Titanium.Web.Proxy/Http/HttpWebClient.cs
+34
-31
TcpConnectionManager.cs
Titanium.Web.Proxy/Http/TcpConnectionManager.cs
+25
-19
RequestHandler.cs
Titanium.Web.Proxy/RequestHandler.cs
+45
-43
ResponseHandler.cs
Titanium.Web.Proxy/ResponseHandler.cs
+20
-21
No files found.
Titanium.Web.Proxy.Test/ProxyTestController.cs
View file @
ffe306c2
...
@@ -43,7 +43,7 @@ namespace Titanium.Web.Proxy.Test
...
@@ -43,7 +43,7 @@ namespace Titanium.Web.Proxy.Test
//Read browser URL send back to proxy by the injection script in OnResponse event
//Read browser URL send back to proxy by the injection script in OnResponse event
public
void
OnRequest
(
object
sender
,
SessionEventArgs
e
)
public
void
OnRequest
(
object
sender
,
SessionEventArgs
e
)
{
{
Console
.
WriteLine
(
e
.
RequestUrl
);
Console
.
WriteLine
(
e
.
ProxySession
.
Request
.
RequestUrl
);
////read request headers
////read request headers
//var requestHeaders = e.RequestHeaders;
//var requestHeaders = e.RequestHeaders;
...
...
Titanium.Web.Proxy/EventArguments/SessionEventArgs.cs
View file @
ffe306c2
This diff is collapsed.
Click to expand it.
Titanium.Web.Proxy/Http/HttpWebClient.cs
View file @
ffe306c2
...
@@ -15,25 +15,29 @@ namespace Titanium.Web.Proxy.Http
...
@@ -15,25 +15,29 @@ namespace Titanium.Web.Proxy.Http
public
class
Request
public
class
Request
{
{
public
string
Method
{
get
;
set
;
}
public
string
Method
{
get
;
set
;
}
public
Uri
RequestUri
{
get
;
set
;
}
public
Uri
RequestUri
{
get
;
set
;
}
public
string
Version
{
get
;
set
;
}
public
string
Version
{
get
;
set
;
}
public
List
<
HttpHeader
>
RequestHeaders
{
get
;
set
;
}
public
string
RequestStatus
{
get
;
set
;
}
public
string
RequestStatus
{
get
;
set
;
}
public
int
RequestContentLength
{
get
;
set
;
}
public
int
RequestContentLength
{
get
;
set
;
}
public
bool
RequestSendChunked
{
get
;
set
;
}
public
bool
RequestSendChunked
{
get
;
set
;
}
public
string
RequestContentType
{
get
;
set
;
}
public
string
RequestContentType
{
get
;
set
;
}
public
bool
RequestKeepAlive
{
get
;
set
;
}
public
bool
RequestKeepAlive
{
get
;
set
;
}
public
string
RequestHost
{
get
;
set
;
}
public
string
RequestHost
{
get
;
set
;
}
public
string
RequestUrl
{
get
;
internal
set
;
}
public
string
RequestHostname
{
get
;
internal
set
;
}
internal
Encoding
RequestEncoding
{
get
;
set
;
}
internal
Version
RequestHttpVersion
{
get
;
set
;
}
internal
bool
RequestIsAlive
{
get
;
set
;
}
internal
bool
CancelRequest
{
get
;
set
;
}
internal
byte
[]
RequestBody
{
get
;
set
;
}
internal
string
RequestBodyString
{
get
;
set
;
}
internal
bool
RequestBodyRead
{
get
;
set
;
}
public
List
<
HttpHeader
>
RequestHeaders
{
get
;
internal
set
;
}
internal
bool
RequestLocked
{
get
;
set
;
}
public
Request
()
public
Request
()
{
{
this
.
RequestHeaders
=
new
List
<
HttpHeader
>();
this
.
RequestHeaders
=
new
List
<
HttpHeader
>();
...
@@ -43,28 +47,28 @@ namespace Titanium.Web.Proxy.Http
...
@@ -43,28 +47,28 @@ namespace Titanium.Web.Proxy.Http
public
class
Response
public
class
Response
{
{
public
List
<
HttpHeader
>
ResponseHeaders
{
get
;
set
;
}
internal
Encoding
ResponseEncoding
{
get
;
set
;
}
internal
Stream
ResponseStream
{
get
;
set
;
}
internal
byte
[]
ResponseBody
{
get
;
set
;
}
internal
string
ResponseBodyString
{
get
;
set
;
}
internal
bool
ResponseBodyRead
{
get
;
set
;
}
internal
bool
ResponseLocked
{
get
;
set
;
}
public
List
<
HttpHeader
>
ResponseHeaders
{
get
;
internal
set
;
}
public
string
ResponseCharacterSet
{
get
;
set
;
}
public
string
ResponseCharacterSet
{
get
;
set
;
}
public
string
ResponseContentEncoding
{
get
;
set
;
}
public
string
ResponseContentEncoding
{
get
;
set
;
}
public
System
.
Version
ResponseProtocolVersion
{
get
;
set
;
}
public
System
.
Version
ResponseProtocolVersion
{
get
;
set
;
}
public
string
ResponseStatusCode
{
get
;
set
;
}
public
string
ResponseStatusCode
{
get
;
set
;
}
public
string
ResponseStatusDescription
{
get
;
set
;
}
public
string
ResponseStatusDescription
{
get
;
set
;
}
public
bool
ResponseKeepAlive
{
get
;
set
;
}
public
bool
ResponseKeepAlive
{
get
;
set
;
}
public
string
ResponseContentType
{
get
;
set
;
}
public
string
ResponseContentType
{
get
;
set
;
}
public
int
ContentLength
{
get
;
set
;
}
public
Response
()
public
Response
()
{
{
this
.
ResponseHeaders
=
new
List
<
HttpHeader
>();
this
.
ResponseHeaders
=
new
List
<
HttpHeader
>();
}
}
public
int
ContentLength
{
get
;
set
;
}
}
}
public
class
HttpWebSession
public
class
HttpWebSession
...
@@ -81,27 +85,26 @@ namespace Titanium.Web.Proxy.Http
...
@@ -81,27 +85,26 @@ namespace Titanium.Web.Proxy.Http
public
Request
Request
{
get
;
set
;
}
public
Request
Request
{
get
;
set
;
}
public
Response
Response
{
get
;
set
;
}
public
Response
Response
{
get
;
set
;
}
public
TcpConnection
Client
{
get
;
set
;
}
public
TcpConnection
Proxy
Client
{
get
;
set
;
}
public
void
SetConnection
(
TcpConnection
Connection
)
public
void
SetConnection
(
TcpConnection
Connection
)
{
{
Client
=
Connection
;
ProxyClient
=
Connection
;
ServerStreamReader
=
Client
.
ServerStreamReader
;
}
}
public
HttpWebSession
()
public
HttpWebSession
()
{
{
this
.
Request
=
new
Request
();
this
.
Request
=
new
Request
();
this
.
Response
=
new
Response
();
this
.
Response
=
new
Response
();
}
}
public
CustomBinaryReader
ServerStreamReader
{
get
;
set
;
}
public
async
Task
SendRequest
()
public
void
SendRequest
()
{
{
Stream
stream
=
Client
.
Stream
;
Stream
stream
=
Proxy
Client
.
Stream
;
StringBuilder
requestLines
=
new
StringBuilder
();
StringBuilder
requestLines
=
new
StringBuilder
();
...
@@ -122,13 +125,13 @@ namespace Titanium.Web.Proxy.Http
...
@@ -122,13 +125,13 @@ namespace Titanium.Web.Proxy.Http
string
request
=
requestLines
.
ToString
();
string
request
=
requestLines
.
ToString
();
byte
[]
requestBytes
=
Encoding
.
ASCII
.
GetBytes
(
request
);
byte
[]
requestBytes
=
Encoding
.
ASCII
.
GetBytes
(
request
);
await
AsyncExtensions
.
WriteAsync
((
Stream
)
stream
,
requestBytes
,
0
,
requestBytes
.
Length
);
stream
.
Write
(
requestBytes
,
0
,
requestBytes
.
Length
);
await
AsyncExtensions
.
FlushAsync
((
Stream
)
stream
);
stream
.
Flush
(
);
}
}
public
void
ReceiveResponse
()
public
void
ReceiveResponse
()
{
{
var
httpResult
=
ServerStreamReader
.
ReadLine
().
Split
(
new
char
[]
{
' '
},
3
);
var
httpResult
=
ProxyClient
.
ServerStreamReader
.
ReadLine
().
Split
(
new
char
[]
{
' '
},
3
);
var
httpVersion
=
httpResult
[
0
];
var
httpVersion
=
httpResult
[
0
];
...
@@ -148,7 +151,7 @@ namespace Titanium.Web.Proxy.Http
...
@@ -148,7 +151,7 @@ namespace Titanium.Web.Proxy.Http
this
.
Response
.
ResponseStatusDescription
=
status
;
this
.
Response
.
ResponseStatusDescription
=
status
;
List
<
string
>
responseLines
=
ServerStreamReader
.
ReadAllLines
();
List
<
string
>
responseLines
=
ProxyClient
.
ServerStreamReader
.
ReadAllLines
();
for
(
int
index
=
0
;
index
<
responseLines
.
Count
;
++
index
)
for
(
int
index
=
0
;
index
<
responseLines
.
Count
;
++
index
)
{
{
...
...
Titanium.Web.Proxy/Http/TcpConnectionManager.cs
View file @
ffe306c2
...
@@ -22,25 +22,28 @@ namespace Titanium.Web.Proxy.Http
...
@@ -22,25 +22,28 @@ namespace Titanium.Web.Proxy.Http
{
{
static
ConcurrentDictionary
<
string
,
ConcurrentStack
<
TcpConnection
>>
ConnectionCache
=
new
ConcurrentDictionary
<
string
,
ConcurrentStack
<
TcpConnection
>>();
static
ConcurrentDictionary
<
string
,
ConcurrentStack
<
TcpConnection
>>
ConnectionCache
=
new
ConcurrentDictionary
<
string
,
ConcurrentStack
<
TcpConnection
>>();
public
static
async
Task
<
TcpConnection
>
GetClient
(
string
Hostname
,
int
port
,
bool
IsSecure
)
public
static
TcpConnection
GetClient
(
string
Hostname
,
int
port
,
bool
IsSecure
)
{
{
var
key
=
string
.
Concat
(
Hostname
,
":"
,
port
,
":"
,
IsSecure
);
var
key
=
string
.
Concat
(
Hostname
,
":"
,
port
,
":"
,
IsSecure
);
ConcurrentStack
<
TcpConnection
>
connections
;
if
(!
ConnectionCache
.
TryGetValue
(
key
,
out
connections
))
{
return
await
CreateClient
(
Hostname
,
port
,
IsSecure
);
}
TcpConnection
client
;
TcpConnection
client
;
if
(!
connections
.
TryPop
(
out
client
)
)
lock
(
ConnectionCache
)
{
{
return
await
CreateClient
(
Hostname
,
port
,
IsSecure
);
ConcurrentStack
<
TcpConnection
>
connections
;
if
(!
ConnectionCache
.
TryGetValue
(
key
,
out
connections
))
{
return
CreateClient
(
Hostname
,
port
,
IsSecure
);
}
if
(!
connections
.
TryPop
(
out
client
))
{
return
CreateClient
(
Hostname
,
port
,
IsSecure
);
}
}
}
return
client
;
return
client
;
}
}
private
static
async
Task
<
TcpConnection
>
CreateClient
(
string
Hostname
,
int
port
,
bool
IsSecure
)
private
static
TcpConnection
CreateClient
(
string
Hostname
,
int
port
,
bool
IsSecure
)
{
{
var
client
=
new
TcpClient
(
Hostname
,
port
);
var
client
=
new
TcpClient
(
Hostname
,
port
);
var
stream
=
(
Stream
)
client
.
GetStream
();
var
stream
=
(
Stream
)
client
.
GetStream
();
...
@@ -51,7 +54,7 @@ namespace Titanium.Web.Proxy.Http
...
@@ -51,7 +54,7 @@ namespace Titanium.Web.Proxy.Http
try
try
{
{
sslStream
=
new
SslStream
(
stream
);
sslStream
=
new
SslStream
(
stream
);
await
AsyncPlatformExtensions
.
AuthenticateAsClientAsync
(
sslStream
,
Hostname
);
sslStream
.
AuthenticateAsClient
(
Hostname
);
stream
=
(
Stream
)
sslStream
;
stream
=
(
Stream
)
sslStream
;
}
}
catch
catch
...
@@ -68,17 +71,20 @@ namespace Titanium.Web.Proxy.Http
...
@@ -68,17 +71,20 @@ namespace Titanium.Web.Proxy.Http
public
static
void
AddClient
(
string
Hostname
,
int
port
,
bool
IsSecure
,
TcpConnection
Client
)
public
static
void
AddClient
(
string
Hostname
,
int
port
,
bool
IsSecure
,
TcpConnection
Client
)
{
{
var
key
=
string
.
Concat
(
Hostname
,
":"
,
port
,
":"
,
IsSecure
);
var
key
=
string
.
Concat
(
Hostname
,
":"
,
port
,
":"
,
IsSecure
);
lock
(
ConnectionCache
)
ConcurrentStack
<
TcpConnection
>
connections
;
if
(!
ConnectionCache
.
TryGetValue
(
key
,
out
connections
))
{
{
connections
=
new
ConcurrentStack
<
TcpConnection
>();
ConcurrentStack
<
TcpConnection
>
connections
;
if
(!
ConnectionCache
.
TryGetValue
(
key
,
out
connections
))
{
connections
=
new
ConcurrentStack
<
TcpConnection
>();
connections
.
Push
(
Client
);
ConnectionCache
.
TryAdd
(
key
,
connections
);
}
connections
.
Push
(
Client
);
connections
.
Push
(
Client
);
ConnectionCache
.
TryAdd
(
key
,
connections
);
}
}
connections
.
Push
(
Client
);
}
}
...
...
Titanium.Web.Proxy/RequestHandler.cs
View file @
ffe306c2
This diff is collapsed.
Click to expand it.
Titanium.Web.Proxy/ResponseHandler.cs
View file @
ffe306c2
...
@@ -26,19 +26,19 @@ namespace Titanium.Web.Proxy
...
@@ -26,19 +26,19 @@ namespace Titanium.Web.Proxy
try
try
{
{
args
.
ResponseHeaders
=
ReadResponseHeaders
(
args
.
ProxySession
);
args
.
ProxySession
.
Response
.
ResponseHeaders
=
ReadResponseHeaders
(
args
.
ProxySession
);
args
.
ResponseStream
=
args
.
ProxySession
.
ServerStreamReader
.
BaseStream
;
args
.
ProxySession
.
Response
.
ResponseStream
=
args
.
ProxySession
.
ProxyClient
.
ServerStreamReader
.
BaseStream
;
if
(
BeforeResponse
!=
null
)
if
(
BeforeResponse
!=
null
)
{
{
args
.
ResponseEncoding
=
args
.
ProxySession
.
GetResponseEncoding
();
args
.
ProxySession
.
Response
.
ResponseEncoding
=
args
.
ProxySession
.
GetResponseEncoding
();
BeforeResponse
(
null
,
args
);
BeforeResponse
(
null
,
args
);
}
}
args
.
ResponseLocked
=
true
;
args
.
ProxySession
.
Response
.
ResponseLocked
=
true
;
if
(
args
.
ResponseBodyRead
)
if
(
args
.
ProxySession
.
Response
.
ResponseBodyRead
)
{
{
var
isChunked
=
args
.
ProxySession
.
Response
.
ResponseHeaders
.
Any
(
x
=>
x
.
Name
.
ToLower
()
==
"transfer-encoding"
&&
x
.
Value
.
ToLower
().
Contains
(
"chunked"
));
var
isChunked
=
args
.
ProxySession
.
Response
.
ResponseHeaders
.
Any
(
x
=>
x
.
Name
.
ToLower
()
==
"transfer-encoding"
&&
x
.
Value
.
ToLower
().
Contains
(
"chunked"
));
var
contentEncoding
=
args
.
ProxySession
.
Response
.
ResponseContentEncoding
;
var
contentEncoding
=
args
.
ProxySession
.
Response
.
ResponseContentEncoding
;
...
@@ -46,40 +46,40 @@ namespace Titanium.Web.Proxy
...
@@ -46,40 +46,40 @@ namespace Titanium.Web.Proxy
switch
(
contentEncoding
.
ToLower
())
switch
(
contentEncoding
.
ToLower
())
{
{
case
"gzip"
:
case
"gzip"
:
args
.
ResponseBody
=
CompressionHelper
.
CompressGzip
(
args
.
ResponseBody
);
args
.
ProxySession
.
Response
.
ResponseBody
=
CompressionHelper
.
CompressGzip
(
args
.
ProxySession
.
Response
.
ResponseBody
);
break
;
break
;
case
"deflate"
:
case
"deflate"
:
args
.
ResponseBody
=
CompressionHelper
.
CompressDeflate
(
args
.
ResponseBody
);
args
.
ProxySession
.
Response
.
ResponseBody
=
CompressionHelper
.
CompressDeflate
(
args
.
ProxySession
.
Response
.
ResponseBody
);
break
;
break
;
case
"zlib"
:
case
"zlib"
:
args
.
ResponseBody
=
CompressionHelper
.
CompressZlib
(
args
.
ResponseBody
);
args
.
ProxySession
.
Response
.
ResponseBody
=
CompressionHelper
.
CompressZlib
(
args
.
ProxySession
.
Response
.
ResponseBody
);
break
;
break
;
}
}
WriteResponseStatus
(
args
.
ProxySession
.
Response
.
ResponseProtocolVersion
,
args
.
ProxySession
.
Response
.
ResponseStatusCode
,
WriteResponseStatus
(
args
.
ProxySession
.
Response
.
ResponseProtocolVersion
,
args
.
ProxySession
.
Response
.
ResponseStatusCode
,
args
.
ProxySession
.
Response
.
ResponseStatusDescription
,
args
.
ClientStreamWriter
);
args
.
ProxySession
.
Response
.
ResponseStatusDescription
,
args
.
Client
.
Client
StreamWriter
);
WriteResponseHeaders
(
args
.
Client
StreamWriter
,
args
.
ResponseHeaders
,
args
.
ResponseBody
.
Length
,
WriteResponseHeaders
(
args
.
Client
.
ClientStreamWriter
,
args
.
ProxySession
.
Response
.
ResponseHeaders
,
args
.
ProxySession
.
Response
.
ResponseBody
.
Length
,
isChunked
);
isChunked
);
WriteResponseBody
(
args
.
Client
Stream
,
args
.
ResponseBody
,
isChunked
);
WriteResponseBody
(
args
.
Client
.
ClientStream
,
args
.
ProxySession
.
Response
.
ResponseBody
,
isChunked
);
}
}
else
else
{
{
var
isChunked
=
args
.
ProxySession
.
Response
.
ResponseHeaders
.
Any
(
x
=>
x
.
Name
.
ToLower
()
==
"transfer-encoding"
&&
x
.
Value
.
ToLower
().
Contains
(
"chunked"
));
var
isChunked
=
args
.
ProxySession
.
Response
.
ResponseHeaders
.
Any
(
x
=>
x
.
Name
.
ToLower
()
==
"transfer-encoding"
&&
x
.
Value
.
ToLower
().
Contains
(
"chunked"
));
WriteResponseStatus
(
args
.
ProxySession
.
Response
.
ResponseProtocolVersion
,
args
.
ProxySession
.
Response
.
ResponseStatusCode
,
WriteResponseStatus
(
args
.
ProxySession
.
Response
.
ResponseProtocolVersion
,
args
.
ProxySession
.
Response
.
ResponseStatusCode
,
args
.
ProxySession
.
Response
.
ResponseStatusDescription
,
args
.
ClientStreamWriter
);
args
.
ProxySession
.
Response
.
ResponseStatusDescription
,
args
.
Client
.
Client
StreamWriter
);
WriteResponseHeaders
(
args
.
Client
StreamWriter
,
args
.
ResponseHeaders
);
WriteResponseHeaders
(
args
.
Client
.
ClientStreamWriter
,
args
.
ProxySession
.
Response
.
ResponseHeaders
);
if
(
isChunked
||
args
.
ProxySession
.
Response
.
ContentLength
>
0
)
if
(
isChunked
||
args
.
ProxySession
.
Response
.
ContentLength
>
0
)
WriteResponseBody
(
args
.
ResponseStream
,
args
.
ClientStream
,
isChunked
,
args
.
ProxySession
.
Response
.
ContentLength
);
WriteResponseBody
(
args
.
ProxySession
.
ProxyClient
.
ServerStreamReader
,
args
.
Client
.
ClientStream
,
isChunked
,
args
.
ProxySession
.
Response
.
ContentLength
);
}
}
args
.
ClientStream
.
Flush
();
args
.
Client
.
Client
Stream
.
Flush
();
}
}
catch
catch
{
{
Dispose
(
args
.
Client
,
args
.
ClientStream
,
args
.
ClientStreamReader
,
args
.
ClientStreamWriter
,
args
);
Dispose
(
args
.
Client
.
TcpClient
,
args
.
Client
.
ClientStream
,
args
.
Client
.
ClientStreamReader
,
args
.
Client
.
ClientStreamWriter
,
args
);
}
}
finally
finally
{
{
...
@@ -199,7 +199,7 @@ namespace Titanium.Web.Proxy
...
@@ -199,7 +199,7 @@ namespace Titanium.Web.Proxy
WriteResponseBodyChunked
(
data
,
clientStream
);
WriteResponseBodyChunked
(
data
,
clientStream
);
}
}
private
static
void
WriteResponseBody
(
Stream
inStream
,
Stream
outStream
,
bool
isChunked
,
int
BodyLength
)
private
static
void
WriteResponseBody
(
CustomBinaryReader
inStreamReader
,
Stream
outStream
,
bool
isChunked
,
int
BodyLength
)
{
{
if
(!
isChunked
)
if
(!
isChunked
)
{
{
...
@@ -213,7 +213,7 @@ namespace Titanium.Web.Proxy
...
@@ -213,7 +213,7 @@ namespace Titanium.Web.Proxy
var
bytesRead
=
0
;
var
bytesRead
=
0
;
var
totalBytesRead
=
0
;
var
totalBytesRead
=
0
;
while
((
bytesRead
+=
inStream
.
Read
(
buffer
,
0
,
bytesToRead
))
>
0
)
while
((
bytesRead
+=
inStream
Reader
.
BaseStream
.
Read
(
buffer
,
0
,
bytesToRead
))
>
0
)
{
{
outStream
.
Write
(
buffer
,
0
,
bytesRead
);
outStream
.
Write
(
buffer
,
0
,
bytesRead
);
totalBytesRead
+=
bytesRead
;
totalBytesRead
+=
bytesRead
;
...
@@ -227,13 +227,12 @@ namespace Titanium.Web.Proxy
...
@@ -227,13 +227,12 @@ namespace Titanium.Web.Proxy
}
}
}
}
else
else
WriteResponseBodyChunked
(
inStream
,
outStream
);
WriteResponseBodyChunked
(
inStream
Reader
,
outStream
);
}
}
//Send chunked response
//Send chunked response
private
static
void
WriteResponseBodyChunked
(
Stream
inStream
,
Stream
outStream
)
private
static
void
WriteResponseBodyChunked
(
CustomBinaryReader
inStreamReader
,
Stream
outStream
)
{
{
var
inStreamReader
=
new
CustomBinaryReader
(
inStream
,
Encoding
.
ASCII
);
while
(
true
)
while
(
true
)
{
{
var
chuchkHead
=
inStreamReader
.
ReadLine
();
var
chuchkHead
=
inStreamReader
.
ReadLine
();
...
...
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