13
13
14
14
namespace Titanium . Web . Proxy . EventArguments
15
15
{
16
- public class Client
17
- {
18
- internal TcpClient TcpClient { get ; set ; }
19
- internal Stream ClientStream { get ; set ; }
20
- internal CustomBinaryReader ClientStreamReader { get ; set ; }
21
- internal StreamWriter ClientStreamWriter { get ; set ; }
22
-
23
- public int ClientPort { get ; internal set ; }
24
- public IPAddress ClientIpAddress { get ; internal set ; }
25
16
26
- }
17
+ /// <summary>
18
+ /// Holds info related to a single proxy session (single request/response sequence)
19
+ /// A proxy session is bounded to a single connection from client
20
+ /// A proxy session ends when client terminates connection to proxy
21
+ /// or when server terminates connection from proxy
22
+ /// </summary>
27
23
public class SessionEventArgs : EventArgs , IDisposable
28
24
{
29
25
readonly int _bufferSize ;
30
26
27
+ /// <summary>
28
+ /// Constructor to initialize the proxy
29
+ /// </summary>
31
30
internal SessionEventArgs ( int bufferSize )
32
31
{
33
32
_bufferSize = bufferSize ;
34
- Client = new Client ( ) ;
33
+ Client = new ProxyClient ( ) ;
35
34
ProxySession = new HttpWebSession ( ) ;
36
35
}
37
36
38
- internal Client Client { get ; set ; }
37
+ /// <summary>
38
+ /// Holds a reference to server connection
39
+ /// </summary>
40
+ internal ProxyClient Client { get ; set ; }
39
41
42
+
43
+ /// <summary>
44
+ /// Does this session uses SSL
45
+ /// </summary>
40
46
public bool IsHttps { get ; internal set ; }
41
47
48
+ /// <summary>
49
+ /// A web session corresponding to a single request/response sequence
50
+ /// within a proxy connection
51
+ /// </summary>
42
52
public HttpWebSession ProxySession { get ; set ; }
43
53
44
54
55
+ /// <summary>
56
+ /// A shortcut to get the request content length
57
+ /// </summary>
45
58
public int RequestContentLength
46
59
{
47
60
get
@@ -50,17 +63,25 @@ public int RequestContentLength
50
63
}
51
64
}
52
65
66
+ /// <summary>
67
+ /// A shortcut to get the request Method (GET/POST/PUT etc)
68
+ /// </summary>
53
69
public string RequestMethod
54
70
{
55
71
get { return ProxySession . Request . Method ; }
56
72
}
57
73
58
-
74
+ /// <summary>
75
+ /// A shortcut to get the response status code (200 OK, 404 etc)
76
+ /// </summary>
59
77
public string ResponseStatusCode
60
78
{
61
79
get { return ProxySession . Response . ResponseStatusCode ; }
62
80
}
63
81
82
+ /// <summary>
83
+ /// A shortcut to get the response content type
84
+ /// </summary>
64
85
public string ResponseContentType
65
86
{
66
87
get
@@ -69,30 +90,39 @@ public string ResponseContentType
69
90
}
70
91
}
71
92
93
+ /// <summary>
94
+ /// implement any cleanup here
95
+ /// </summary>
72
96
public void Dispose ( )
73
97
{
74
98
75
99
}
76
100
101
+ /// <summary>
102
+ /// Read request body content as bytes[] for current session
103
+ /// </summary>
77
104
private void ReadRequestBody ( )
78
105
{
106
+ //GET request don't have a request body to read
79
107
if ( ( ProxySession . Request . Method . ToUpper ( ) != "POST" && ProxySession . Request . Method . ToUpper ( ) != "PUT" ) )
80
108
{
81
109
throw new BodyNotFoundException ( "Request don't have a body." +
82
110
"Please verify that this request is a Http POST/PUT and request content length is greater than zero before accessing the body." ) ;
83
111
}
84
112
113
+ //Caching check
85
114
if ( ProxySession . Request . RequestBody == null )
86
115
{
87
116
var isChunked = false ;
88
117
string requestContentEncoding = null ;
89
118
90
-
119
+ //get compression method (gzip, zlib etc)
91
120
if ( ProxySession . Request . RequestHeaders . Any ( x => x . Name . ToLower ( ) == "content-encoding" ) )
92
121
{
93
122
requestContentEncoding = ProxySession . Request . RequestHeaders . First ( x => x . Name . ToLower ( ) == "content-encoding" ) . Value ;
94
123
}
95
124
125
+ //check if the request have chunked body (body send chunck by chunck without a fixed length)
96
126
if ( ProxySession . Request . RequestHeaders . Any ( x => x . Name . ToLower ( ) == "transfer-encoding" ) )
97
127
{
98
128
var transferEncoding =
@@ -103,13 +133,14 @@ private void ReadRequestBody()
103
133
}
104
134
}
105
135
106
-
136
+ //If not chunked then its easy just read the whole body with the content length mentioned in the request header
107
137
if ( requestContentEncoding == null && ! isChunked )
108
138
ProxySession . Request . RequestBody = this . Client . ClientStreamReader . ReadBytes ( RequestContentLength ) ;
109
139
else
110
140
{
111
141
using ( var requestBodyStream = new MemoryStream ( ) )
112
142
{
143
+ //For chunked request we need to read data as they arrive, until we reach a chunk end symbol
113
144
if ( isChunked )
114
145
{
115
146
while ( true )
@@ -126,6 +157,7 @@ private void ReadRequestBody()
126
157
}
127
158
else
128
159
{
160
+ //chunk end
129
161
this . Client . ClientStreamReader . ReadLine ( ) ;
130
162
break ;
131
163
}
@@ -134,6 +166,7 @@ private void ReadRequestBody()
134
166
135
167
try
136
168
{
169
+ //decompress
137
170
switch ( requestContentEncoding )
138
171
{
139
172
case "gzip" :
@@ -152,20 +185,29 @@ private void ReadRequestBody()
152
185
}
153
186
catch
154
187
{
188
+ //if decompression fails, just assign the body stream as it it
189
+ //Not a safe option
155
190
ProxySession . Request . RequestBody = requestBodyStream . ToArray ( ) ;
156
191
}
157
192
}
158
193
}
159
194
}
195
+ //Now set the flag to true
196
+ //So that next time we can deliver body from cache
160
197
ProxySession . Request . RequestBodyRead = true ;
161
198
}
162
199
200
+ /// <summary>
201
+ /// Read response body as byte[] for current response
202
+ /// </summary>
163
203
private void ReadResponseBody ( )
164
204
{
205
+ //If not already read (not cached yet)
165
206
if ( ProxySession . Response . ResponseBody == null )
166
207
{
167
208
using ( var responseBodyStream = new MemoryStream ( ) )
168
209
{
210
+ //If chuncked the read chunk by chunk until we hit chunk end symbol
169
211
if ( ProxySession . Response . IsChunked )
170
212
{
171
213
while ( true )
@@ -182,17 +224,19 @@ private void ReadResponseBody()
182
224
}
183
225
else
184
226
{
227
+ //chuck end
185
228
ProxySession . ProxyClient . ServerStreamReader . ReadLine ( ) ;
186
229
break ;
187
230
}
188
231
}
189
232
}
190
233
else
191
234
{
235
+ //If not chunked then its easy just read the amount of bytes mentioned in content length header of response
192
236
var buffer = ProxySession . ProxyClient . ServerStreamReader . ReadBytes ( ProxySession . Response . ContentLength ) ;
193
237
responseBodyStream . Write ( buffer , 0 , buffer . Length ) ;
194
238
}
195
-
239
+ //decompress
196
240
switch ( ProxySession . Response . ContentEncoding )
197
241
{
198
242
case "gzip" :
@@ -209,41 +253,46 @@ private void ReadResponseBody()
209
253
break ;
210
254
}
211
255
}
212
-
256
+ //set this to true for caching
213
257
ProxySession . Response . ResponseBodyRead = true ;
214
258
}
215
259
}
216
260
217
-
218
- public Encoding GetRequestBodyEncoding ( )
219
- {
220
- if ( ProxySession . Request . RequestLocked ) throw new Exception ( "You cannot call this function after request is made to server." ) ;
221
-
222
- return ProxySession . Request . Encoding ;
223
- }
224
-
261
+ /// <summary>
262
+ /// Gets the request body as bytes
263
+ /// </summary>
264
+ /// <returns></returns>
225
265
public byte [ ] GetRequestBody ( )
226
266
{
227
267
if ( ProxySession . Request . RequestLocked ) throw new Exception ( "You cannot call this function after request is made to server." ) ;
228
268
229
269
ReadRequestBody ( ) ;
230
270
return ProxySession . Request . RequestBody ;
231
271
}
232
-
272
+ /// <summary>
273
+ /// Gets the request body as string
274
+ /// </summary>
275
+ /// <returns></returns>
233
276
public string GetRequestBodyAsString ( )
234
277
{
235
278
if ( ProxySession . Request . RequestLocked ) throw new Exception ( "You cannot call this function after request is made to server." ) ;
236
279
237
280
238
281
ReadRequestBody ( ) ;
239
282
283
+ //Use the encoding specified in request to decode the byte[] data to string
240
284
return ProxySession . Request . RequestBodyString ?? ( ProxySession . Request . RequestBodyString = ProxySession . Request . Encoding . GetString ( ProxySession . Request . RequestBody ) ) ;
241
285
}
242
286
287
+ /// <summary>
288
+ /// Sets the request body
289
+ /// </summary>
290
+ /// <param name="body"></param>
243
291
public void SetRequestBody ( byte [ ] body )
244
292
{
245
293
if ( ProxySession . Request . RequestLocked ) throw new Exception ( "You cannot call this function after request is made to server." ) ;
246
294
295
+ //syphon out the request body from client before setting the new body
247
296
if ( ! ProxySession . Request . RequestBodyRead )
248
297
{
249
298
ReadRequestBody ( ) ;
@@ -253,10 +302,15 @@ public void SetRequestBody(byte[] body)
253
302
ProxySession . Request . RequestBodyRead = true ;
254
303
}
255
304
305
+ /// <summary>
306
+ /// Sets the body with the specified string
307
+ /// </summary>
308
+ /// <param name="body"></param>
256
309
public void SetRequestBodyString ( string body )
257
310
{
258
311
if ( ProxySession . Request . RequestLocked ) throw new Exception ( "You cannot call this function after request is made to server." ) ;
259
312
313
+ //syphon out the request body from client before setting the new body
260
314
if ( ! ProxySession . Request . RequestBodyRead )
261
315
{
262
316
ReadRequestBody ( ) ;
@@ -266,13 +320,10 @@ public void SetRequestBodyString(string body)
266
320
ProxySession . Request . RequestBodyRead = true ;
267
321
}
268
322
269
- public Encoding GetResponseBodyEncoding ( )
270
- {
271
- if ( ! ProxySession . Request . RequestLocked ) throw new Exception ( "You cannot call this function before request is made to server." ) ;
272
-
273
- return ProxySession . Response . Encoding ;
274
- }
275
-
323
+ /// <summary>
324
+ /// Gets the response body as byte array
325
+ /// </summary>
326
+ /// <returns></returns>
276
327
public byte [ ] GetResponseBody ( )
277
328
{
278
329
if ( ! ProxySession . Request . RequestLocked ) throw new Exception ( "You cannot call this function before request is made to server." ) ;
@@ -281,6 +332,10 @@ public byte[] GetResponseBody()
281
332
return ProxySession . Response . ResponseBody ;
282
333
}
283
334
335
+ /// <summary>
336
+ /// Gets the response body as string
337
+ /// </summary>
338
+ /// <returns></returns>
284
339
public string GetResponseBodyAsString ( )
285
340
{
286
341
if ( ! ProxySession . Request . RequestLocked ) throw new Exception ( "You cannot call this function before request is made to server." ) ;
@@ -290,10 +345,15 @@ public string GetResponseBodyAsString()
290
345
return ProxySession . Response . ResponseBodyString ?? ( ProxySession . Response . ResponseBodyString = ProxySession . Response . Encoding . GetString ( ProxySession . Response . ResponseBody ) ) ;
291
346
}
292
347
348
+ /// <summary>
349
+ /// Set the response body bytes
350
+ /// </summary>
351
+ /// <param name="body"></param>
293
352
public void SetResponseBody ( byte [ ] body )
294
353
{
295
354
if ( ! ProxySession . Request . RequestLocked ) throw new Exception ( "You cannot call this function before request is made to server." ) ;
296
355
356
+ //syphon out the response body from server before setting the new body
297
357
if ( ProxySession . Response . ResponseBody == null )
298
358
{
299
359
GetResponseBody ( ) ;
@@ -302,10 +362,15 @@ public void SetResponseBody(byte[] body)
302
362
ProxySession . Response . ResponseBody = body ;
303
363
}
304
364
365
+ /// <summary>
366
+ /// Replace the response body with the specified string
367
+ /// </summary>
368
+ /// <param name="body"></param>
305
369
public void SetResponseBodyString ( string body )
306
370
{
307
371
if ( ! ProxySession . Request . RequestLocked ) throw new Exception ( "You cannot call this function before request is made to server." ) ;
308
372
373
+ //syphon out the response body from server before setting the new body
309
374
if ( ProxySession . Response . ResponseBody == null )
310
375
{
311
376
GetResponseBody ( ) ;
@@ -316,6 +381,14 @@ public void SetResponseBodyString(string body)
316
381
}
317
382
318
383
384
+ /// <summary>
385
+ /// Before request is made to server
386
+ /// Respond with the specified HTML string to client
387
+ /// and ignore the request
388
+ /// Marking as obsolete, need to comeup with a generic responder method in future
389
+ /// </summary>
390
+ /// <param name="html"></param>
391
+ [ Obsolete ]
319
392
public void Ok ( string html )
320
393
{
321
394
if ( ProxySession . Request . RequestLocked ) throw new Exception ( "You cannot call this function after request is made to server." ) ;
0 commit comments