Subversion Repositories general

Rev

Rev 1234 | Rev 1238 | Go to most recent revision | Details | Compare with Previous | Last modification | View Log | RSS feed

Rev Author Line No. Line
1092 dev 1
using System;
2
using System.Collections;
1199 dev 3
using System.IO;
1092 dev 4
using System.Net;
5
using System.Net.Sockets;
6
using System.Threading;
7
using System.Text;
8
using System.Text.RegularExpressions;
9
using System.Xml;
10
 
1234 dev 11
// FIXME:
12
//   - deny write access to all public properties
13
//   - for text/xml get encoding from body if not specified in header
14
//   - option to not store parsed data, just raw packets and reparse on demand
15
//   - implement all others (not 'identity' and 'chunked') transfer- and content- encodings
16
//   - benchmark one-by-one byte iterator vs. block read
17
//   - locks for HttpMessage in parser
1092 dev 18
namespace TCPproxy
19
{
1199 dev 20
	public enum BinLogTypes
21
	{
22
		None = 1,
23
		TcpConnection
24
	}
25
 
1092 dev 26
	public enum LogLevel
27
	{
28
		Critical,
29
		Error,
30
		Warning,
31
		Important,
32
		Info,
33
		Debug
34
	}
35
 
36
	public enum SocketState
37
	{
38
		None,
39
		Connecting,
40
		Connected,
41
		ShutdownSend,
1122 dev 42
		ShutdownReceived,
1092 dev 43
		Closed
44
	}
45
 
46
	public enum TcpMessageDirection
47
	{
1199 dev 48
		None,
1092 dev 49
		Local,
50
		Remote
51
	}
52
 
53
	public enum HttpVersion
54
	{
55
		V0_9,
56
		V1_0,
57
		V1_1
58
	}
59
 
1233 dev 60
	public enum HttpTransferEncoding
1092 dev 61
	{
1233 dev 62
		None,              // there is no body
63
		Identity,
64
		Chunked,
1092 dev 65
		Gzip,
66
		Compress,
67
		Deflate,
68
		Unknown
69
	}
70
 
1233 dev 71
	public enum HttpContentEncoding
72
	{
73
		None,              // there is no body
74
		Identity,
75
		Gzip,
76
		Compress,
77
		Deflate,
78
		Unknown
79
	}
80
 
1092 dev 81
	public class TcpLogEventArgs : EventArgs
82
	{
83
		private readonly LogLevel  level;
84
		private readonly string    message;
85
		private readonly Exception exception;
86
 
87
		public LogLevel Level
88
		{
89
			get { return level; }
90
		}
91
 
92
		public string Message
93
		{
94
			get { return message; }
95
		}
96
 
97
		public Exception Exception
98
		{
99
			get { return exception; }
100
		}
101
 
102
		internal TcpLogEventArgs(LogLevel level, string message, Exception exception)
103
		{
104
			this.level     = level;
105
			this.message   = message;
106
			this.exception = exception;
107
		}
108
	}
109
 
110
	public class TcpEventArgs : EventArgs
111
	{
112
		internal TcpEventArgs()
113
		{
114
		}
115
	}
116
 
117
	public class TcpConnectionEventArgs : EventArgs
118
	{
119
		private readonly TcpConnection tcp;
120
 
121
		public TcpConnection Tcp
122
		{
123
			get { return tcp; }
124
		}
125
 
126
		internal TcpConnectionEventArgs(TcpConnection tcp)
127
		{
128
			this.tcp = tcp;
129
		}
130
	}
131
 
132
	public class TcpHttpEventArgs : EventArgs
133
	{
134
		private readonly HttpMessage http;
135
 
136
		public HttpMessage Http
137
		{
138
			get { return http; }
139
		}
140
 
141
		internal TcpHttpEventArgs(HttpMessage http)
142
		{
143
			this.http = http;
144
		}
145
	}
146
 
147
	public delegate void TcpLogEventHandler(object sender, TcpLogEventArgs e);
148
 
149
	public delegate void TcpEventHandler(object sender, TcpEventArgs e);
150
 
151
	public delegate void TcpConnectionEventHandler(object sender, TcpConnectionEventArgs e);
152
 
153
	public delegate void TcpHttpEventHandler(object sender, TcpHttpEventArgs e);
154
 
155
	public class TcpListener
156
	{
157
		private int       listenPort     = -1;
158
		private IPAddress resendHost;
159
		private int       resendPort     = -1;
160
		private Socket    socket;
161
		private int       tcpId          = 0;
162
		private ArrayList tcpConnections = new ArrayList();
163
 
164
		public TcpListener(int listenPort, IPAddress resendHost, int resendPort)
165
		{
166
			this.listenPort = listenPort;
167
			this.resendHost = resendHost;
168
			this.resendPort = resendPort;
169
		}
170
 
171
		public void StartListening()
172
		{
173
			socket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
174
			socket.Bind(new IPEndPoint(IPAddress.Any, listenPort));
175
			socket.Listen(100);
1232 dev 176
			ThreadDebugger.Add(socket.BeginAccept(new AsyncCallback(OnClientConnect), null), "StartListening");
1092 dev 177
			SendLog(null, LogLevel.Important, "Listen on " + socket.LocalEndPoint);
178
		}
1122 dev 179
 
1092 dev 180
		public void StopListening()
181
		{
1122 dev 182
			try
1092 dev 183
			{
184
				if(socket != null)
185
				{
186
					SendLog(null, LogLevel.Important, "Stop listening " + socket.LocalEndPoint);
187
					socket.Close();
188
				}
189
			}
190
			catch(ObjectDisposedException) // socket is already closed
191
			{
1122 dev 192
			}
193
			catch(Exception ex)
194
			{
1092 dev 195
				Console.WriteLine(ex.Message + " (" + ex.GetType().Name + ")\n" + ex.StackTrace);
196
			}
197
		}
198
 
199
		public void CancelAll()
200
		{
201
			ArrayList tcpConnectionsCopy;
202
 
203
			lock(tcpConnections)
204
			{
205
				tcpConnectionsCopy = new ArrayList(tcpConnections);
206
			}
207
 
208
			foreach(TcpConnection tcp in tcpConnectionsCopy)
209
			{
210
				tcp.Cancel();
211
			}
212
		}
213
 
214
		protected virtual void OnClientConnect(IAsyncResult asyn)
215
		{
1122 dev 216
			try
1092 dev 217
			{
218
				Socket worker = socket.EndAccept(asyn);
1232 dev 219
				ThreadDebugger.Add(socket.BeginAccept(new AsyncCallback(OnClientConnect), null), "OnClientConnect"); // wait for next client
1092 dev 220
 
221
				TcpConnection tcp = new TcpConnection(string.Format("{0:0000}", tcpId++));
222
				tcp.Close += new TcpEventHandler(TcpConnectionClosed);
223
				OnNewTcp(new TcpConnectionEventArgs(tcp));
224
 
1122 dev 225
				lock(tcpConnections)
1092 dev 226
				{
227
					tcpConnections.Add(tcp);
228
				}
229
 
230
				tcp.Continue(resendHost, resendPort, worker);
231
			}
232
			catch(ObjectDisposedException) {}  // socket is closed
1122 dev 233
			catch(Exception ex)
1092 dev 234
			{
235
				Console.WriteLine(ex.Message + " (" + ex.GetType().Name + ")\n" + ex.StackTrace);
236
			}
237
		}
238
 
239
		protected virtual void TcpConnectionClosed(object sender, TcpEventArgs e)
240
		{
241
			lock(tcpConnections)
242
			{
243
				tcpConnections.Remove((TcpConnection)sender);
244
			}
245
		}
246
 
247
		public event TcpConnectionEventHandler NewTcp;
248
 
249
		protected virtual void OnNewTcp(TcpConnectionEventArgs e)
250
		{
1122 dev 251
			if(NewTcp != null)
1092 dev 252
			{
1122 dev 253
				NewTcp(this, e);
1092 dev 254
			}
255
		}
256
 
257
		public event TcpLogEventHandler Log;
258
 
259
		protected virtual void OnLog(TcpLogEventArgs e)
260
		{
1122 dev 261
			if(Log != null)
1092 dev 262
			{
1122 dev 263
				Log(this, e);
1092 dev 264
			}
265
		}
266
 
267
		protected virtual void SendLog(TcpConnection tcp, LogLevel level, string message)
268
		{
269
			TcpLogEventArgs e = new TcpLogEventArgs(level, message, null);
270
			OnLog(e);
271
		}
272
 
273
		protected virtual void SendLog(TcpConnection tcp, LogLevel level, Exception ex)
274
		{
275
			TcpLogEventArgs e = new TcpLogEventArgs(level, null, ex);
276
			OnLog(e);
277
		}
1199 dev 278
 
279
		public void ReadBinLog(BinaryReader reader)
280
		{
281
			// tcp connections
282
			TcpConnection tcp;
283
			while((tcp = TcpConnection.ReadBinLog(reader)) != null) {
284
				OnNewTcp(new TcpConnectionEventArgs(tcp));
285
			}
286
		}
1092 dev 287
	}
288
 
289
	public class TcpConnection
290
	{
1234 dev 291
		private string             id;
292
		private DateTime           startTimestamp     = DateTime.MinValue;
293
		private DateTime           localEndTimestamp  = DateTime.MinValue;
294
		private DateTime           remoteEndTimestamp = DateTime.MinValue;
295
		private IPEndPoint         localPoint;
296
		private IPEndPoint         remotePoint;
297
		private LinkedList         messages           = new LinkedList();
298
		private LinkedListReadOnly messagesReadOnly;
299
		private SocketState        localState         = SocketState.None;
300
		private SocketState        remoteState        = SocketState.None;
301
		private SocketWorker       worker;
302
		private LinkedList         https              = new LinkedList();
303
		private HttpParser         httpParser;
1092 dev 304
 
305
		public string Id
306
		{
307
			get { return id; }
308
		}
309
 
310
		public DateTime StartTimestamp
311
		{
312
			get { return startTimestamp; }
313
		}
314
 
315
		public DateTime LocalEndTimestamp
316
		{
317
			get { return localEndTimestamp; }
318
		}
319
 
320
		public DateTime RemoteEndTimestamp
321
		{
322
			get { return remoteEndTimestamp; }
323
		}
324
 
325
		public IPEndPoint LocalPoint
326
		{
327
			get { return localPoint; }
328
		}
329
 
330
		public IPEndPoint RemotePoint
331
		{
332
			get { return remotePoint; }
333
		}
334
 
1234 dev 335
		public LinkedListReadOnly Messages
1092 dev 336
		{
1234 dev 337
			get { return new LinkedListReadOnly(messages); }
1092 dev 338
		}
339
 
340
		public SocketState LocalState
341
		{
342
			get { return localState; }
343
		}
344
 
345
		public SocketState RemoteState
346
		{
347
			get { return remoteState; }
348
		}
349
 
350
		private int CountBytes(TcpMessageDirection direction)
351
		{
352
			int count = 0;
353
 
354
			foreach(TcpMessage message in messages)
355
			{
356
				if(message.Direction == direction)
357
					count += message.Length;
358
			}
359
			return count;
360
		}
361
 
362
		public int SentBytes
363
		{
364
			get { return CountBytes(TcpMessageDirection.Local); }
365
		}
366
 
367
		public int ReceivedBytes
368
		{
369
			get { return CountBytes(TcpMessageDirection.Remote); }
370
		}
371
 
372
		internal TcpConnection(string id)
373
		{
1234 dev 374
			this.id               = id;
375
			this.httpParser       = HttpParser.Parse(this);
376
			this.messagesReadOnly = new LinkedListReadOnly(messages);
1092 dev 377
		}
378
 
379
		internal void Continue(IPAddress resendHost, int resendPort, Socket localSocket)
380
		{
381
			SendLog(LogLevel.Important, "Client connected from " + ((IPEndPoint)localSocket.RemoteEndPoint).ToString());
382
			SetLocalState(SocketState.Connected);
383
			this.worker = new SocketWorker(resendHost, resendPort, localSocket, this);
384
		}
385
 
386
		public void Cancel()
387
		{
1199 dev 388
			if(worker != null)
389
				worker.Cancel();
1092 dev 390
		}
391
 
392
		protected TcpMessage Append(TcpMessageDirection direction, byte[] newBytes)
393
		{
394
			return Append(direction, newBytes, newBytes.Length);
395
		}
396
 
397
		protected TcpMessage Append(TcpMessageDirection direction, byte[] newBytes, int length)
398
		{
399
			if(newBytes == null) return null;
400
 
401
			TcpMessage message;
402
 
1122 dev 403
			lock(this)
1092 dev 404
			{
405
				message = new TcpMessage();
406
				message.Direction = direction;
407
				messages.Add(message);
408
				message.Append(newBytes, length);
409
			}
410
 
411
			httpParser.NewMessageArived();
412
			OnUpdate(new TcpEventArgs());
413
 
414
			return message;
415
		}
416
 
417
		internal void AddHttpMessage(HttpMessage http)
418
		{
419
			lock(this)
420
			{
421
				https.Add(http);
422
				TcpHttpEventArgs e = new TcpHttpEventArgs(http);
423
				OnNewHttp(e);
424
			}
425
		}
426
 
1235 dev 427
        public override string ToString() // FIXME delete the method
428
        {
429
            return id + " " + startTimestamp.ToString("HH:mm:ss.ffff");
430
        }
431
 
432
        protected void SetLocalPoint(IPEndPoint localPoint)
1092 dev 433
		{
1122 dev 434
			this.localPoint = localPoint;
1092 dev 435
			OnUpdate(new TcpEventArgs());
436
		}
437
 
438
		protected void SetRemotePoint(IPEndPoint remotePoint)
439
		{
1122 dev 440
			this.remotePoint = remotePoint;
1092 dev 441
			OnUpdate(new TcpEventArgs());
442
		}
443
 
444
		protected void SetLocalState(SocketState localState)
445
		{
1122 dev 446
			if(this.localState == SocketState.None && localState == SocketState.Connecting)
1092 dev 447
			{
448
				startTimestamp = DateTime.Now;
449
			}
1122 dev 450
			else if(this.localState == SocketState.None && localState == SocketState.Connected)
1092 dev 451
			{
452
				startTimestamp = DateTime.Now;
453
			}
1122 dev 454
			else if(this.localState == SocketState.None && localState == SocketState.Closed)
1092 dev 455
			{
456
			}
1122 dev 457
			else if(this.localState == SocketState.Connecting && localState == SocketState.Connected)
1092 dev 458
			{
459
			}
1122 dev 460
			else if(this.localState == SocketState.Connecting && localState == SocketState.Closed)
1092 dev 461
			{
462
				if(localEndTimestamp == DateTime.MinValue) localEndTimestamp = DateTime.Now;
463
			}
1122 dev 464
			else if(this.localState == SocketState.Connected && localState == SocketState.ShutdownSend)
1092 dev 465
			{
466
			}
1122 dev 467
			else if(this.localState == SocketState.Connected && localState == SocketState.ShutdownReceived)
1092 dev 468
			{
469
				if(localEndTimestamp == DateTime.MinValue) localEndTimestamp = DateTime.Now;
470
			}
1122 dev 471
			else if(this.localState == SocketState.Connected && localState == SocketState.Closed)
1092 dev 472
			{
473
				if(localEndTimestamp == DateTime.MinValue) localEndTimestamp = DateTime.Now;
474
			}
1122 dev 475
			else if(this.localState == SocketState.ShutdownSend && localState == SocketState.Closed)
1092 dev 476
			{
477
				if(localEndTimestamp == DateTime.MinValue) localEndTimestamp = DateTime.Now;
478
			}
1122 dev 479
			else if(this.localState == SocketState.ShutdownSend && localState == SocketState.ShutdownReceived)
1092 dev 480
			{
481
				if(localEndTimestamp == DateTime.MinValue) localEndTimestamp = DateTime.Now;
482
			}
1122 dev 483
			else if(this.localState == SocketState.ShutdownReceived && localState == SocketState.ShutdownSend)
1092 dev 484
			{
485
			}
1122 dev 486
			else if(this.localState == SocketState.ShutdownReceived && localState == SocketState.Closed)
1092 dev 487
			{
488
				if(localEndTimestamp == DateTime.MinValue) localEndTimestamp = DateTime.Now;
489
			}
1122 dev 490
			else if(this.localState == SocketState.Closed && localState == SocketState.Closed)
1092 dev 491
			{
492
				if(localEndTimestamp == DateTime.MinValue) localEndTimestamp = DateTime.Now;
493
			}
1122 dev 494
			else
1092 dev 495
			{
496
				throw new Exception("Wrong local socket state change: from " + this.localState + " to " + localState);
497
			}
1122 dev 498
			this.localState = localState;
1092 dev 499
			if(this.localState == SocketState.Closed) httpParser.NewMessageArived();
500
			OnUpdate(new TcpEventArgs());
501
		}
502
 
503
		protected void SetRemoteState(SocketState remoteState)
504
		{
1122 dev 505
			if(this.remoteState == SocketState.None && remoteState == SocketState.Connecting)
1092 dev 506
			{
507
			}
1122 dev 508
			else if(this.remoteState == SocketState.None && remoteState == SocketState.Connected)
1092 dev 509
			{
510
			}
1122 dev 511
			else if(this.remoteState == SocketState.None && remoteState == SocketState.Closed)
1092 dev 512
			{
513
			}
1122 dev 514
			else if(this.remoteState == SocketState.Connecting && remoteState == SocketState.Connected)
1092 dev 515
			{
516
			}
1122 dev 517
			else if(this.remoteState == SocketState.Connecting && remoteState == SocketState.Closed)
1092 dev 518
			{
519
				if(remoteEndTimestamp == DateTime.MinValue) remoteEndTimestamp = DateTime.Now;
520
			}
1122 dev 521
			else if(this.remoteState == SocketState.Connected && remoteState == SocketState.ShutdownSend)
1092 dev 522
			{
523
			}
1122 dev 524
			else if(this.remoteState == SocketState.Connected && remoteState == SocketState.ShutdownReceived)
1092 dev 525
			{
526
				if(remoteEndTimestamp == DateTime.MinValue) remoteEndTimestamp = DateTime.Now;
527
			}
1122 dev 528
			else if(this.remoteState == SocketState.Connected && remoteState == SocketState.Closed)
1092 dev 529
			{
530
				if(remoteEndTimestamp == DateTime.MinValue) remoteEndTimestamp = DateTime.Now;
531
			}
1122 dev 532
			else if(this.remoteState == SocketState.ShutdownSend && remoteState == SocketState.Closed)
1092 dev 533
			{
534
				if(remoteEndTimestamp == DateTime.MinValue) remoteEndTimestamp = DateTime.Now;
535
			}
1122 dev 536
			else if(this.remoteState == SocketState.ShutdownSend && remoteState == SocketState.ShutdownReceived)
1092 dev 537
			{
538
				if(remoteEndTimestamp == DateTime.MinValue) remoteEndTimestamp = DateTime.Now;
539
			}
1122 dev 540
			else if(this.remoteState == SocketState.ShutdownReceived && remoteState == SocketState.ShutdownSend)
1092 dev 541
			{
542
			}
1122 dev 543
			else if(this.remoteState == SocketState.ShutdownReceived && remoteState == SocketState.Closed)
1092 dev 544
			{
545
				if(remoteEndTimestamp == DateTime.MinValue) remoteEndTimestamp = DateTime.Now;
546
			}
1122 dev 547
			else if(this.remoteState == SocketState.Closed && remoteState == SocketState.Closed)
1092 dev 548
			{
549
				if(remoteEndTimestamp == DateTime.MinValue) remoteEndTimestamp = DateTime.Now;
550
			}
1122 dev 551
			else
1092 dev 552
			{
553
				throw new Exception("Wrong remote socket state change: from " + this.remoteState + " to " + remoteState);
554
			}
1122 dev 555
			this.remoteState = remoteState;
1092 dev 556
			if(this.remoteState == SocketState.Closed) httpParser.NewMessageArived();
557
			OnUpdate(new TcpEventArgs());
558
		}
559
 
560
		public event TcpEventHandler Update;
561
 
562
		protected virtual void OnUpdate(TcpEventArgs e)
563
		{
1122 dev 564
			if(Update != null)
1092 dev 565
			{
1122 dev 566
				Update(this, e);
1092 dev 567
			}
568
		}
569
 
570
		public event TcpHttpEventHandler NewHttp;
571
 
572
		protected virtual void OnNewHttp(TcpHttpEventArgs e)
573
		{
1122 dev 574
			if(NewHttp != null)
1092 dev 575
			{
1122 dev 576
				NewHttp(this, e);
1092 dev 577
			}
578
		}
579
 
580
		public event TcpEventHandler Close;
581
 
582
		protected virtual void OnClose(TcpEventArgs e)
583
		{
1122 dev 584
			if(Close != null)
1092 dev 585
			{
1122 dev 586
				Close(this, e);
1092 dev 587
			}
588
		}
589
 
590
		public event TcpLogEventHandler Log;
591
 
592
		protected virtual void OnLog(TcpLogEventArgs e)
593
		{
1122 dev 594
			if(Log != null)
1092 dev 595
			{
1122 dev 596
				Log(this, e);
1092 dev 597
			}
598
		}
599
 
600
		protected virtual void SendLog(LogLevel level, string message)
601
		{
602
			TcpLogEventArgs e = new TcpLogEventArgs(level, message, null);
603
			OnLog(e);
604
		}
605
 
606
		protected virtual void SendLog(LogLevel level, Exception ex)
607
		{
608
			TcpLogEventArgs e = new TcpLogEventArgs(level, null, ex);
609
			OnLog(e);
610
		}
611
 
1199 dev 612
		private void WriteEndPoint(BinaryWriter writer, IPEndPoint endPoint)
613
		{
614
			// end point as (family as int, ip length, ip as bytes, port)
615
			byte[] ipBuf = endPoint.Address.GetAddressBytes();
616
			writer.Write((UInt32)endPoint.AddressFamily);
617
			writer.Write((UInt32)ipBuf.Length);
618
			writer.Write(ipBuf);
619
			writer.Write((UInt32)endPoint.Port);
620
		}
621
 
622
		public void WriteBinLog(BinaryWriter writer)
623
		{
624
			// header
625
			writer.Write((byte)BinLogTypes.TcpConnection);
626
 
627
			// id as (length, UTF-8)
628
			byte[] idBuf = Encoding.UTF8.GetBytes(id);
629
			writer.Write((UInt32)idBuf.Length);
630
			writer.Write(idBuf);
631
 
632
			// timestamps as ticks
633
			writer.Write((UInt64)startTimestamp.Ticks);
634
			writer.Write((UInt64)localEndTimestamp.Ticks);
635
			writer.Write((UInt64)remoteEndTimestamp.Ticks);
636
 
637
			// end points as (family as int, ip length, ip as bytes, port)
638
			WriteEndPoint(writer, localPoint);
639
			WriteEndPoint(writer, remotePoint);
640
 
641
			// states as byte
642
			writer.Write((byte)localState);
643
			writer.Write((byte)remoteState);
644
 
645
			// each tcp message as (direction as byte, timestamp in ticks, length, content)
646
			foreach(TcpMessage message in messages) {
647
				writer.Write((byte)message.Direction);
648
				writer.Write((UInt64)message.Timestamp.Ticks);
649
				writer.Write((UInt32)message.Length);
650
				writer.Write(message.Bytes, 0, message.Length);
651
			}
652
 
653
			// end of stream marker
654
			writer.Write((byte)TcpMessageDirection.None);
655
		}
656
 
657
		private static IPEndPoint ReadEndPoint(BinaryReader reader)
658
		{
659
			// end point as (family as int, ip length, ip as bytes, port)
660
			AddressFamily fam           = (AddressFamily)reader.ReadInt32();
661
			int           addressLength = reader.ReadInt32();
662
			byte[]        addressBytes  = reader.ReadBytes(addressLength);
663
			int           port          = reader.ReadInt32();
664
			IPAddress     address       = new IPAddress(addressBytes);
665
 
666
			return new IPEndPoint(address, port);
667
		}
668
 
669
		internal static TcpConnection ReadBinLog(BinaryReader reader)
670
		{
671
			// header
672
			BinLogTypes recordType = (BinLogTypes)reader.ReadByte();
673
 
674
			if(recordType == BinLogTypes.None)
675
				return null;
676
			else if(recordType == BinLogTypes.TcpConnection) {
677
			}
678
			else
679
				throw new Exception("Wrong data type");
680
 
681
			// id as (length, UTF-8)
682
			int    idLength = (int)reader.ReadUInt32();
683
			string id       = Encoding.UTF8.GetString(reader.ReadBytes(idLength));
684
 
685
			TcpConnection tcp = new TcpConnection(id);
686
 
687
			// timestamps as ticks
688
			tcp.startTimestamp     = new DateTime((long)reader.ReadUInt64());
689
			tcp.localEndTimestamp  = new DateTime((long)reader.ReadUInt64());
690
			tcp.remoteEndTimestamp = new DateTime((long)reader.ReadUInt64());
691
 
692
			// end points as (family as int, ip length, ip as bytes, port)
693
			tcp.localPoint  = ReadEndPoint(reader);
694
			tcp.remotePoint = ReadEndPoint(reader);
695
 
696
			// states as byte - read but ignore
697
			reader.ReadByte();
698
			reader.ReadByte();
699
 
700
			// each tcp message as (direction as byte, timestamp in ticks, length, content)
701
			tcp.localState  = SocketState.Closed;
702
			tcp.remoteState = SocketState.Closed;
703
			for(;;) {
704
				TcpMessageDirection direction = (TcpMessageDirection)reader.ReadByte();
705
				if(direction == TcpMessageDirection.None) break; // end of stream marker
706
 
707
				DateTime timestamp = new DateTime((long)reader.ReadUInt64());
708
				int      bufLength = (int)reader.ReadUInt32();
709
				byte[]   buf       = reader.ReadBytes(bufLength);
710
 
711
				TcpMessage msg = tcp.Append(direction, buf);
712
				msg.SetTimestamp(timestamp);
713
			}
714
			tcp.OnUpdate(new TcpEventArgs());
715
 
716
			return tcp;
717
		}
718
 
1092 dev 719
		protected class SocketWorker
720
		{
721
			private enum SendCommandType
722
			{
723
				Send,
724
				Shutdown,
725
				Reset
726
			}
727
 
728
			private class SendCommand
729
			{
730
				public byte[]          buffer  = null;
731
				public int             length  = 0;
1122 dev 732
				public SendCommandType cmdType = SendCommandType.Send;
1092 dev 733
			}
734
 
735
			private static int BUF_SIZE = 2048;
736
 
737
			private TcpConnection    tcp;
738
			private Socket           localSocket;
739
			private Socket           remoteSocket;
740
			private byte[]           localDataBuffer;
741
			private byte[]           remoteDataBuffer;
742
			private AsyncCallback    receiveLocalMethod;
743
			private AsyncCallback    receiveRemoteMethod;
744
			private Queue            localSendQueue              = new Queue();
745
			private Queue            remoteSendQueue             = new Queue();
746
			private AutoResetEvent   localSendEvent              = new AutoResetEvent(false);
747
			private AutoResetEvent   remoteSendEvent             = new AutoResetEvent(false);
748
			private bool             localSocketSendShutdown     = false;
749
			private bool             localSocketReceiveShutdown  = false;
750
			private bool             remoteSocketSendShutdown    = false;
751
			private bool             remoteSocketReceiveShutdown = false;
752
			private ManualResetEvent remoteSocketEvent           = new ManualResetEvent(false);
753
			private Thread           localSendThread;
754
			private Thread           remoteSendThread;
755
 
756
			public SocketWorker(IPAddress resendHost, int resendPort, Socket localSocket, TcpConnection tcp)
757
			{
1122 dev 758
				try
1092 dev 759
				{
1122 dev 760
					tcp.SendLog(LogLevel.Debug, string.Format("Local socket: {0}:{1} <-> {2}:{3}",
761
						((IPEndPoint)localSocket.LocalEndPoint).Address,
1092 dev 762
						((IPEndPoint)localSocket.LocalEndPoint).Port,
1122 dev 763
						((IPEndPoint)localSocket.RemoteEndPoint).Address,
1092 dev 764
						((IPEndPoint)localSocket.RemoteEndPoint).Port));
765
 
766
					this.localSocket    = localSocket;
767
					this.tcp            = tcp;
768
					receiveLocalMethod  = new AsyncCallback(OnLocalReceived);
769
					receiveRemoteMethod = new AsyncCallback(OnRemoteReceived);
770
 
771
					tcp.SetLocalPoint((IPEndPoint)localSocket.RemoteEndPoint);
772
					this.localSocket.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.NoDelay, 1);
1122 dev 773
 
1092 dev 774
					localSendThread = new Thread(new ThreadStart(LocalSendProc));
1232 dev 775
					ThreadDebugger.Add(localSendThread, "LocalSendProc");
1092 dev 776
					localSendThread.Name = "SocketWorker.LocalSendProc";
777
					localSendThread.Start();
778
 
779
					ContinueLocalReceive();
1122 dev 780
 
1092 dev 781
					if(resendHost == null)
782
					{
783
						remoteSocket = null;
784
					}
785
					else
786
					{
787
						tcp.SetRemoteState(SocketState.Connecting);
788
 
789
						IPEndPoint point = new IPEndPoint(resendHost, resendPort);
790
						remoteSocket = new Socket(point.AddressFamily, SocketType.Stream, ProtocolType.Tcp);
791
						remoteSocket.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.NoDelay, 1);
792
						remoteSocket.Connect(point);
793
						tcp.SetRemoteState(SocketState.Connected);
794
						tcp.SetRemotePoint((IPEndPoint)remoteSocket.RemoteEndPoint);
795
 
796
						remoteSendThread = new Thread(new ThreadStart(RemoteSendProc));
1232 dev 797
						ThreadDebugger.Add(remoteSendThread, "RemoteSendProc");
1092 dev 798
						remoteSendThread.Name = "SocketWorker.RemoteSendProc";
799
						remoteSendThread.Start();
800
 
801
						ContinueRemoteReceive();
802
						remoteSocketEvent.Set(); // remote socket ready to send data
803
						tcp.SendLog(LogLevel.Info, "Connected to server " + tcp.RemotePoint.ToString());
804
 
1122 dev 805
						tcp.SendLog(LogLevel.Debug, string.Format("Remote socket: {0}:{1} <-> {2}:{3}",
806
							((IPEndPoint)remoteSocket.LocalEndPoint).Address,
1092 dev 807
							((IPEndPoint)remoteSocket.LocalEndPoint).Port,
1122 dev 808
							((IPEndPoint)remoteSocket.RemoteEndPoint).Address,
1092 dev 809
							((IPEndPoint)remoteSocket.RemoteEndPoint).Port));
810
					}
811
				}
812
				catch(Exception ex)
813
				{
814
					tcp.SendLog(LogLevel.Warning, ex);
815
					Cancel();
816
				}
817
			}
818
 
819
			private void ContinueLocalReceive()
820
			{
1122 dev 821
				try
1092 dev 822
				{
823
					localDataBuffer = new byte[BUF_SIZE];
1232 dev 824
					ThreadDebugger.Add(
825
						localSocket.BeginReceive(localDataBuffer, 0, BUF_SIZE, SocketFlags.None, receiveLocalMethod, this),
826
						"ContinueLocalReceive");
1092 dev 827
				}
828
				catch(ObjectDisposedException ex) // the socket is closed
829
				{
830
					tcp.SendLog(LogLevel.Info, ex);
831
					Cancel();
832
				}
833
				catch(Exception ex)
834
				{
835
					tcp.SendLog(LogLevel.Warning, ex);
836
					Cancel();
837
				}
838
			}
839
 
840
			private void ContinueRemoteReceive()
841
			{
1122 dev 842
				try
1092 dev 843
				{
844
					remoteDataBuffer = new byte[BUF_SIZE];
1232 dev 845
					ThreadDebugger.Add(
846
						remoteSocket.BeginReceive(remoteDataBuffer, 0, BUF_SIZE, SocketFlags.None, receiveRemoteMethod, this),
847
						"ContinueRemoteReceive");
1092 dev 848
				}
849
				catch(ObjectDisposedException ex) // the socket is closed
850
				{
851
					tcp.SendLog(LogLevel.Info, ex);
852
					Cancel();
853
				}
854
				catch(Exception ex)
855
				{
856
					tcp.SendLog(LogLevel.Warning, ex);
857
					Cancel();
858
				}
859
			}
860
 
861
			private void CheckLocalSocket()
862
			{
1122 dev 863
				lock(localSocket)
1092 dev 864
				{
1122 dev 865
					try
1092 dev 866
					{
867
						if(localSocketReceiveShutdown && localSocketSendShutdown)
868
						{
869
							if(localSocket.Connected) localSocket.Close();
870
							tcp.SetLocalState(SocketState.Closed);
871
						}
872
					}
873
					catch(Exception ex) // in any case we want to close the socket
874
					{
875
						tcp.SendLog(LogLevel.Warning, ex);
876
					}
877
				}
878
			}
879
 
880
			private void CheckRemoteSocket()
881
			{
1122 dev 882
				lock(remoteSocket)
1092 dev 883
				{
1122 dev 884
					try
1092 dev 885
					{
1122 dev 886
						if(remoteSocketReceiveShutdown && remoteSocketSendShutdown)
1092 dev 887
						{
888
							if(remoteSocket.Connected) remoteSocket.Close();
889
							tcp.SetRemoteState(SocketState.Closed);
890
						}
891
					}
892
					catch(Exception ex) // in any case we want to close the socket
893
					{
894
						tcp.SendLog(LogLevel.Warning, ex);
895
					}
896
				}
897
			}
898
 
899
			private void OnLocalReceived(IAsyncResult asyn)
900
			{
1122 dev 901
				try
1092 dev 902
				{
903
					int  bytesReceived = 0;
904
					bool reset         = false;
905
 
906
					try
907
					{
908
						bytesReceived = localSocket.EndReceive(asyn);
909
					}
910
					catch(ObjectDisposedException)
911
					{
912
						reset = true;
913
					}
914
					catch(SocketException ex)
915
					{
1122 dev 916
						if(ex.ErrorCode == 10054)
1092 dev 917
							reset = true;
1122 dev 918
						else
1092 dev 919
							throw ex;
920
					}
921
 
922
					if(reset)
923
					{
924
						tcp.SendLog(LogLevel.Info, "Got reset from local end");
925
 
926
						lock(localSocket)
927
						{
928
							if(localSocket.Connected) localSocket.Close();
929
							tcp.SetLocalState(SocketState.Closed);
930
						}
931
 
932
						SendCommand cmd = new SendCommand();
933
						cmd.cmdType = SendCommandType.Reset;
934
						lock(localSendQueue)
935
						{
936
							localSendQueue.Enqueue(cmd);
937
							localSendEvent.Set();
938
						}
939
					}
940
					else if(bytesReceived <= 0)
941
					{
942
						tcp.SendLog(LogLevel.Info, "Got showdown from local end");
943
 
944
						localSocket.Shutdown(SocketShutdown.Receive);
1122 dev 945
						tcp.SetLocalState(SocketState.ShutdownReceived);
1092 dev 946
						localSocketReceiveShutdown = true;
947
						CheckLocalSocket();
948
 
949
						SendCommand cmd = new SendCommand();
950
						cmd.cmdType = SendCommandType.Shutdown;
951
						lock(localSendQueue)
952
						{
953
							localSendQueue.Enqueue(cmd);
954
							localSendEvent.Set();
955
						}
956
					}
957
					else
958
					{
959
						tcp.SendLog(LogLevel.Debug, string.Format("Local received {0} bytes", bytesReceived));
960
 
961
						SendCommand cmd = new SendCommand();
962
						cmd.buffer = localDataBuffer;
963
						cmd.length = bytesReceived;
964
						lock(localSendQueue)
965
						{
966
							localSendQueue.Enqueue(cmd);
967
							localSendEvent.Set();
968
						}
969
						ContinueLocalReceive();
970
					}
971
				}
972
				catch(Exception ex)
973
				{
974
					tcp.SendLog(LogLevel.Warning, ex);
975
					Cancel();
976
				}
977
			}
978
 
979
			private void LocalSendProc()
980
			{
981
				try
982
				{
1122 dev 983
					while(true)
1092 dev 984
					{
985
						SendCommand cmd;
986
 
1122 dev 987
						if(localSendQueue.Count == 0)
1092 dev 988
						{
989
							localSendEvent.WaitOne();
990
						}
991
 
1122 dev 992
						lock(localSendQueue)
1092 dev 993
						{
994
							localSendEvent.Reset();
995
							cmd = (SendCommand)localSendQueue.Dequeue();
996
						}
997
 
998
						if(cmd.cmdType == SendCommandType.Reset) // reset marker
999
						{
1000
							if(remoteSocket == null || !remoteSocket.Connected) remoteSocketEvent.WaitOne();
1001
							tcp.SendLog(LogLevel.Debug, string.Format("Send reset to remote end"));
1002
							lock(remoteSocket)
1003
							{
1004
								if(!remoteSocket.Connected) remoteSocket.Close();
1005
								tcp.SetRemoteState(SocketState.Closed);
1006
							}
1007
 
1008
							break; // no more send allowed
1009
						}
1010
						else if(cmd.cmdType == SendCommandType.Shutdown) // shutdown marker
1011
						{
1012
							if(remoteSocket == null || !remoteSocket.Connected) remoteSocketEvent.WaitOne();
1013
							tcp.SendLog(LogLevel.Debug, string.Format("Send shutdown to remote end"));
1014
							remoteSocket.Shutdown(SocketShutdown.Send);
1015
							tcp.SetRemoteState(SocketState.ShutdownSend);
1016
							remoteSocketSendShutdown = true;
1017
							CheckRemoteSocket();
1018
 
1019
							break; // no more send allowed
1020
						}
1021
						else
1022
						{
1023
							// store received bytes
1024
							tcp.Append(TcpMessageDirection.Local, cmd.buffer, cmd.length);
1025
 
1026
							// forward it
1027
							if(remoteSocket == null || !remoteSocket.Connected) remoteSocketEvent.WaitOne();
1028
							tcp.SendLog(LogLevel.Debug, string.Format("Send {0} bytes to remote end", cmd.length));
1029
							remoteSocket.Send(cmd.buffer, cmd.length, SocketFlags.None);
1030
						}
1031
					}
1032
				}
1033
				catch(ThreadAbortException)
1034
				{
1035
				}
1036
				catch(Exception ex)
1037
				{
1038
					tcp.SendLog(LogLevel.Warning, ex);
1039
					Cancel();
1040
				}
1041
			}
1042
 
1043
			private void OnRemoteReceived(IAsyncResult asyn)
1044
			{
1122 dev 1045
				try
1092 dev 1046
				{
1047
					int  bytesReceived = 0;
1048
					bool reset         = false;
1049
 
1050
					try
1051
					{
1052
						bytesReceived = remoteSocket.EndReceive(asyn);
1053
					}
1054
					catch(ObjectDisposedException)
1055
					{
1056
						reset = true;
1057
					}
1058
					catch(SocketException ex)
1059
					{
1122 dev 1060
						if(ex.ErrorCode == 10054)
1092 dev 1061
							reset = true;
1122 dev 1062
						else
1092 dev 1063
							throw ex;
1064
					}
1065
 
1066
					if(reset)
1067
					{
1068
						tcp.SendLog(LogLevel.Info, "Got reset from remote end");
1069
 
1070
						lock(remoteSocket)
1071
						{
1072
							if(remoteSocket.Connected) remoteSocket.Close();
1073
							tcp.SetRemoteState(SocketState.Closed);
1074
						}
1075
 
1076
						SendCommand cmd = new SendCommand();
1077
						cmd.cmdType = SendCommandType.Reset;
1078
						lock(remoteSendQueue)
1079
						{
1080
							remoteSendQueue.Enqueue(cmd);
1081
							remoteSendEvent.Set();
1082
						}
1083
					}
1084
					else if(bytesReceived <= 0)
1085
					{
1086
						tcp.SendLog(LogLevel.Info, "Got showdown from remote end");
1087
 
1088
						remoteSocket.Shutdown(SocketShutdown.Receive);
1122 dev 1089
						tcp.SetRemoteState(SocketState.ShutdownReceived);
1092 dev 1090
						remoteSocketReceiveShutdown = true;
1091
						CheckRemoteSocket();
1092
 
1093
						SendCommand cmd = new SendCommand();
1094
						cmd.cmdType = SendCommandType.Shutdown;
1095
						lock(remoteSendQueue)
1096
						{
1097
							remoteSendQueue.Enqueue(cmd);
1098
							remoteSendEvent.Set();
1099
						}
1100
					}
1101
					else
1102
					{
1103
						tcp.SendLog(LogLevel.Debug, string.Format("Remote received {0} bytes", bytesReceived));
1104
 
1105
						SendCommand cmd = new SendCommand();
1106
						cmd.buffer = remoteDataBuffer;
1107
						cmd.length = bytesReceived;
1108
						lock(remoteSendQueue)
1109
						{
1110
							remoteSendQueue.Enqueue(cmd);
1111
							remoteSendEvent.Set();
1112
						}
1113
						ContinueRemoteReceive();
1114
					}
1115
				}
1116
				catch(Exception ex)
1117
				{
1118
					tcp.SendLog(LogLevel.Warning, ex);
1119
					Cancel();
1120
				}
1121
			}
1122
 
1123
			private void RemoteSendProc()
1124
			{
1122 dev 1125
				try
1092 dev 1126
				{
1122 dev 1127
					while(true)
1092 dev 1128
					{
1129
						SendCommand cmd;
1130
 
1122 dev 1131
						if(remoteSendQueue.Count == 0)
1092 dev 1132
						{
1133
							remoteSendEvent.WaitOne();
1134
						}
1135
 
1122 dev 1136
						lock(remoteSendQueue)
1092 dev 1137
						{
1138
							remoteSendEvent.Reset();
1139
							cmd = (SendCommand)remoteSendQueue.Dequeue();
1140
						}
1141
 
1142
						if(cmd.cmdType == SendCommandType.Reset) // reset marker
1143
						{
1144
							tcp.SendLog(LogLevel.Debug, string.Format("Send reset to local end"));
1145
							lock(localSocket)
1146
							{
1147
								if(localSocket.Connected) localSocket.Close();
1148
								tcp.SetLocalState(SocketState.Closed);
1149
							}
1150
 
1151
							break; // no more send allowed
1152
						}
1153
						else if(cmd.cmdType == SendCommandType.Shutdown) // shutdown marker
1154
						{
1155
							tcp.SendLog(LogLevel.Debug, string.Format("Send shutdown to local end"));
1156
							localSocket.Shutdown(SocketShutdown.Send);
1157
							tcp.SetLocalState(SocketState.ShutdownSend);
1158
							localSocketSendShutdown = true;
1159
							CheckLocalSocket();
1160
 
1161
							break; // no more send allowed
1162
						}
1163
						else
1164
						{
1165
							// store received bytes
1166
							tcp.Append(TcpMessageDirection.Remote, cmd.buffer, cmd.length);
1167
 
1168
							// forward it
1169
							tcp.SendLog(LogLevel.Debug, string.Format("Send {0} bytes to local end", cmd.length));
1170
							localSocket.Send(cmd.buffer, cmd.length, SocketFlags.None);
1171
						}
1172
					}
1173
				}
1174
				catch(ThreadAbortException)
1175
				{
1176
				}
1177
				catch(Exception ex)
1178
				{
1179
					tcp.SendLog(LogLevel.Warning, ex);
1180
					Cancel();
1181
				}
1182
			}
1183
 
1184
			public void Cancel()
1185
			{
1186
				tcp.SendLog(LogLevel.Important, "Connection canceled");
1187
 
1122 dev 1188
				try
1092 dev 1189
				{
1190
					if(localSendThread != null  && localSendThread.IsAlive)  localSendThread.Abort();
1191
					if(remoteSendThread != null && remoteSendThread.IsAlive) remoteSendThread.Abort();
1192
 
1193
					// close sockets
1122 dev 1194
					try
1092 dev 1195
					{
1122 dev 1196
						if(localSocket != null)
1092 dev 1197
						{
1198
							lock(localSocket)
1199
							{
1200
								if(localSocket.Connected) localSocket.Close();
1201
							}
1202
						}
1203
					}
1204
					catch(Exception ex) // in any case we want to close the socket
1205
					{
1206
						tcp.SendLog(LogLevel.Warning, ex);
1207
					}
1208
					tcp.SetLocalState(SocketState.Closed);
1209
 
1122 dev 1210
					try
1092 dev 1211
					{
1212
						if(remoteSocket != null)
1213
						{
1214
							lock(remoteSocket)
1215
							{
1216
								if(remoteSocket.Connected) remoteSocket.Close();
1217
							}
1218
						}
1219
					}
1220
					catch(Exception ex) // in any case we want to close the socket
1221
					{
1222
						tcp.SendLog(LogLevel.Warning, ex);
1223
					}
1224
					tcp.SetRemoteState(SocketState.Closed);
1225
 
1226
					// return
1227
					tcp.OnClose(new TcpEventArgs());
1228
				}
1229
				catch(Exception ex)
1230
				{
1231
					tcp.SendLog(LogLevel.Warning, ex);
1232
				}
1233
			}
1234
		}
1235
	}
1236
 
1237
	internal class HttpParser
1238
	{
1239
		private enum HttpCharType
1240
		{
1241
			None,
1242
			Control,
1243
			Digit,
1244
			UpAlpha,
1245
			LoAlpha,
1246
			NonChar,
1247
			Separator,
1248
			CrLf,
1249
		}
1250
 
1251
		private static HttpCharType[] charTypes  = null;
1252
		private static bool[]         tokenChars = null;
1122 dev 1253
		private static char[]         charValues = {
1125 dev 1254
			 '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0',
1255
			 '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0',
1256
			 ' ',  '!',  '"',  '#',  '$',  '%',  '&',  '\'', '(',  ')',  '*',  '+',  ',',  '-',  '.',  '/',
1257
			 '0',  '1',  '2',  '3',  '4',  '5',  '6',  '7',  '8',  '9',  ':',  ';',  '<',  '=',  '>',  '?',
1258
			 '@',  'A',  'B',  'C',  'D',  'E',  'F',  'G',  'H',  'I',  'J',  'K',  'L',  'M',  'N',  'O',
1259
			 'P',  'Q',  'R',  'S',  'T',  'U',  'V',  'W',  'X',  'Y',  'Z',  '[',  '\\', ']',  '^',  '_',
1260
			 '`',  'a',  'b',  'c',  'd',  'e',  'f',  'g',  'h',  'i',  'j',  'k',  'l',  'm',  'n',  'o',
1261
			 'p',  'q',  'r',  's',  't',  'u',  'v',  'w',  'x',  'y',  'z',  '{',  '|',  '}',  '~',  '\0'
1262
		 };
1092 dev 1263
 
1264
		private static void InitTables()
1265
		{
1266
			if(charTypes != null) return;
1267
 
1268
			// main table
1269
			charTypes = new HttpCharType[256];
1270
 
1271
			for(int i = 0; i < charTypes.Length; i++) charTypes[i] = HttpCharType.None;
1272
 
1273
			for(int i = 0; i <= 31; i++) charTypes[i] = HttpCharType.Control;
1274
			charTypes[127] = HttpCharType.Control;   // <del>
1275
 
1276
			for(int i = 48; i <= 57; i++) charTypes[i] = HttpCharType.Digit;
1277
 
1278
			for(int i = 65; i <=  90; i++) charTypes[i] = HttpCharType.UpAlpha;
1279
			for(int i = 97; i <= 122; i++) charTypes[i] = HttpCharType.LoAlpha;
1280
 
1281
			for(int i = 128; i < charTypes.Length; i++) charTypes[i] = HttpCharType.NonChar;
1282
 
1283
			charTypes[ 40] = HttpCharType.Separator;   // (
1284
			charTypes[ 41] = HttpCharType.Separator;   // )
1285
			charTypes[ 60] = HttpCharType.Separator;   // <
1286
			charTypes[ 62] = HttpCharType.Separator;   // >
1287
			charTypes[ 64] = HttpCharType.Separator;   // @
1288
			charTypes[ 44] = HttpCharType.Separator;   // ,
1289
			charTypes[ 59] = HttpCharType.Separator;   // ;
1290
			charTypes[ 58] = HttpCharType.Separator;   // :
1291
			charTypes[ 92] = HttpCharType.Separator;   // \
1292
			charTypes[ 34] = HttpCharType.Separator;   // "
1293
			charTypes[ 47] = HttpCharType.Separator;   // /
1294
			charTypes[ 91] = HttpCharType.Separator;   // [
1295
			charTypes[ 93] = HttpCharType.Separator;   // ]
1296
			charTypes[ 63] = HttpCharType.Separator;   // ?
1297
			charTypes[ 61] = HttpCharType.Separator;   // =
1298
			charTypes[123] = HttpCharType.Separator;   // {
1299
			charTypes[125] = HttpCharType.Separator;   // }
1300
			charTypes[ 32] = HttpCharType.Separator;   // <space>
1301
			charTypes[  9] = HttpCharType.Separator;   // <tab>
1302
 
1303
			charTypes[ 13] = HttpCharType.CrLf;        // <CR>
1304
			charTypes[ 10] = HttpCharType.CrLf;        // <LF>
1305
 
1306
			// token table
1307
			tokenChars = new bool[256];
1122 dev 1308
			for(int i = 0; i < tokenChars.Length; i++)
1092 dev 1309
			{
1122 dev 1310
				tokenChars[i] = !(charTypes[i] == HttpCharType.NonChar
1092 dev 1311
					|| charTypes[i] == HttpCharType.Control || charTypes[i] == HttpCharType.Separator
1312
					|| charTypes[i] == HttpCharType.CrLf);
1313
			}
1314
		}
1315
 
1316
		private class ParsePosition
1317
		{
1318
			private TcpConnection  messages;
1319
			private IEnumerator    messagesEnum;
1320
			private TcpMessage     tcp    = null;
1321
			private int            tcpPos;
1322
			private int            tcpLen;
1323
			private bool           tcpEnd = false;
1324
			private AutoResetEvent newMessageEvent;
1325
			private AutoResetEvent nextMessageEvent;
1326
 
1327
			public ParsePosition(TcpConnection messages, AutoResetEvent nextMessageEvent)
1328
			{
1329
				this.messages         = messages;
1330
				this.messagesEnum     = messages.Messages.GetEnumerator();
1331
				this.newMessageEvent  = new AutoResetEvent(false);
1332
				this.nextMessageEvent = nextMessageEvent;
1333
			}
1334
 
1335
			public AutoResetEvent NewMessageEvent
1336
			{
1337
				get { return newMessageEvent; }
1338
			}
1339
 
1340
			public bool IsEnd
1341
			{
1342
				get { return tcpEnd; }
1343
			}
1344
 
1345
			public TcpMessage CurrentMessage
1346
			{
1347
				get { return tcp; }
1348
			}
1349
 
1350
			private bool MoveNext()
1351
			{
1122 dev 1352
				for(bool moved = false; !moved; )
1092 dev 1353
				{
1354
					lock(messages)
1355
					{
1356
						newMessageEvent.Reset();
1357
						moved = messagesEnum.MoveNext();
1199 dev 1358
 
1359
						if(!moved && messages.LocalState == SocketState.Closed && messages.RemoteState == SocketState.Closed)
1360
							return false;
1092 dev 1361
					}
1362
 
1363
					if(moved) break;
1364
 
1122 dev 1365
					if(!newMessageEvent.WaitOne())
1092 dev 1366
						throw new Exception("Cannot get next TCP message");
1367
 
1368
					lock(messages)
1369
					{
1370
						if(messages.LocalState == SocketState.Closed && messages.RemoteState == SocketState.Closed)
1371
							return false;
1372
 
1373
						moved = messagesEnum.MoveNext();
1374
					}
1375
				}
1376
 
1377
				return true;
1378
			}
1379
 
1380
			private void NextTcp()
1381
			{
1382
				if(tcpEnd) return;
1383
 
1384
				TcpMessage newTcp = null;
1385
 
1122 dev 1386
				do
1092 dev 1387
				{
1388
					if(!MoveNext())
1389
					{
1390
						tcpEnd = true;
1391
						break;
1392
					}
1393
					newTcp = (TcpMessage)messagesEnum.Current;
1394
				}
1395
				while(tcp != null && tcp.Direction != newTcp.Direction);
1202 dev 1396
				// FIXME correct? no hang?
1092 dev 1397
 
1398
				if(!tcpEnd)
1399
				{
1400
					tcp    = newTcp;
1401
					tcpLen = tcp.Length;
1233 dev 1402
					tcpPos = -1;
1092 dev 1403
					if(nextMessageEvent != null) nextMessageEvent.Set();
1404
				}
1405
			}
1406
 
1233 dev 1407
			public void Back()
1092 dev 1408
			{
1233 dev 1409
				tcpPos--; // FIXME double check if it's always possible to go to _one_ step back
1092 dev 1410
			}
1411
 
1412
			public byte NextOctet()
1413
			{
1414
				tcpPos++;
1415
 
1233 dev 1416
				if(tcp == null || tcpPos >= tcpLen)
1417
				{
1418
					NextTcp();
1419
					tcpPos++;
1420
				}
1092 dev 1421
				if(tcpEnd) return 0;
1422
 
1423
				return tcp.Bytes[tcpPos];
1424
			}
1425
 
1233 dev 1426
			public byte NextOctetAndBack()
1427
			{
1428
				byte b = NextOctet();
1429
				if(!tcpEnd) Back();
1430
 
1431
				return b;
1432
			}
1433
 
1092 dev 1434
			public void SetDirection(TcpMessageDirection direction)
1435
			{
1122 dev 1436
				do
1092 dev 1437
				{
1438
					if(!MoveNext())
1439
					{
1440
						tcp    = null;
1441
						tcpEnd = true;
1442
						break;
1443
					}
1444
					tcp = (TcpMessage)messagesEnum.Current;
1445
				}
1446
				while(tcp.Direction != direction);
1447
 
1448
				if(!tcpEnd)
1449
				{
1450
					tcpLen = tcp.Length;
1233 dev 1451
					tcpPos = -1;
1092 dev 1452
				}
1453
			}
1454
		}
1455
 
1199 dev 1456
		private TcpConnection    messages;
1457
		private AutoResetEvent   requestEvent     = new AutoResetEvent(false); // new request found
1458
		private AutoResetEvent   nextMessageEvent = new AutoResetEvent(false); // request goes to next TCP message
1459
		private LinkedList       https            = new LinkedList();
1460
		private ParsePosition    requestPos;
1461
		private ParsePosition    responsePos;
1462
		private Thread           runThread;
1092 dev 1463
 
1464
		public static HttpParser Parse(TcpConnection messages)
1465
		{
1466
			HttpParser parser = new HttpParser(messages);
1467
			parser.runThread = new Thread(new ThreadStart(parser.Run));
1232 dev 1468
			ThreadDebugger.Add(parser.runThread, "HttpParser.Run");
1199 dev 1469
			parser.runThread.Name = "HttpParser.Run";
1092 dev 1470
			parser.runThread.Start();
1471
 
1472
			return parser;
1473
		}
1474
 
1475
		public void NewMessageArived()
1476
		{
1477
			requestPos.NewMessageEvent.Set();
1478
			responsePos.NewMessageEvent.Set();
1479
		}
1480
 
1481
		public Thread RunThread
1482
		{
1483
			get { return runThread; }
1484
		}
1485
 
1486
		private HttpParser(TcpConnection messages)
1487
		{
1199 dev 1488
			this.messages    = messages;
1489
			this.requestPos  = new ParsePosition(messages, nextMessageEvent);
1490
			this.responsePos = new ParsePosition(messages, null);
1092 dev 1491
			InitTables();
1492
		}
1493
 
1494
		/// <summary>
1495
		/// Try to recognize the stored TCP packets as sequence of HTTP messages (request-response)
1496
		/// </summary>
1497
		private void Run()
1498
		{
1499
			Thread responseThread = null;
1500
 
1122 dev 1501
			try
1092 dev 1502
			{
1503
				responseThread = new Thread(new ThreadStart(MatchResponses));
1232 dev 1504
				ThreadDebugger.Add(responseThread, "MatchResponses");
1092 dev 1505
				responseThread.Name = "HttpParser.MatchResponses";
1506
				responseThread.Start();
1507
 
1508
				// find requests
1122 dev 1509
				while(!requestPos.IsEnd)
1092 dev 1510
				{
1511
					HttpMessage http = new HttpMessage();
1122 dev 1512
					lock(https)
1092 dev 1513
					{
1514
						https.Add(http);
1515
						requestEvent.Set(); // new request available
1516
					}
1517
 
1518
					messages.AddHttpMessage(http);
1519
					SkipEmptyLines(requestPos);
1234 dev 1520
                    http.Request.StartTimestamp = requestPos.CurrentMessage.Timestamp;
1092 dev 1521
 
1522
					ParseRequestLine(requestPos, http);
1523
					http.UpdateHttpMessage();
1524
 
1234 dev 1525
					ParseHeaders(requestPos, http, http.Request);
1526
					SetRequestProperties(http, http.Request);
1092 dev 1527
					http.UpdateHttpMessage();
1122 dev 1528
 
1234 dev 1529
					ParseBody(requestPos, http, http.Request);
1530
					if("text" == http.Request.ContentType && "xml" == http.Request.ContentSubtype)
1092 dev 1531
					{
1234 dev 1532
						http.Request.Xml = new XmlMessage(http.Request.Text);
1092 dev 1533
					}
1534
					http.UpdateHttpMessage();
1535
 
1234 dev 1536
					http.Request.Complete = true;
1092 dev 1537
					http.UpdateHttpMessage();
1538
 
1539
					SkipEmptyLines(requestPos);
1540
				}
1541
 
1542
				responseThread.Join();
1543
			}
1122 dev 1544
			catch(Exception ex)
1092 dev 1545
			{
1546
				Console.WriteLine(ex.Message + " (" + ex.GetType().Name + ")\n" + ex.StackTrace);
1547
				if(responseThread != null) responseThread.Abort();
1548
			}
1549
		}
1550
 
1551
		private void MatchResponses()
1552
		{
1122 dev 1553
			try
1092 dev 1554
			{
1555
				IEnumerator httpEnum = https.GetEnumerator();
1556
 
1557
				if(!nextMessageEvent.WaitOne()) throw new Exception("Cannot get first message of request");
1558
 
1122 dev 1559
				responsePos.SetDirection(requestPos.CurrentMessage.Direction == TcpMessageDirection.Local
1092 dev 1560
					? TcpMessageDirection.Remote : TcpMessageDirection.Local);
1122 dev 1561
 
1562
				while(!responsePos.IsEnd)
1092 dev 1563
				{
1564
					bool moved;
1565
 
1566
					lock(https)
1567
					{
1568
						requestEvent.Reset();
1569
						moved = httpEnum.MoveNext();
1570
					}
1571
 
1122 dev 1572
					if(!moved)
1092 dev 1573
					{
1122 dev 1574
						if(!requestEvent.WaitOne())
1092 dev 1575
							throw new Exception("Cannot get next request");
1576
 
1577
						lock(https)
1578
						{
1122 dev 1579
							if(!httpEnum.MoveNext())
1234 dev 1580
								throw new Exception("Tried to find response but no HTTP message available");
1092 dev 1581
						}
1582
					}
1583
 
1584
					HttpMessage http = (HttpMessage)httpEnum.Current;
1585
 
1234 dev 1586
					ParseResponse(responsePos, http);
1587
 
1588
					if(http.Response.StatusCode == 100) // "100 (Continue)" response
1092 dev 1589
					{
1234 dev 1590
						http.GotContinueResponse();
1591
						ParseResponse(responsePos, http); // once again
1092 dev 1592
					}
1593
 
1234 dev 1594
					http.Response.Complete = true;
1092 dev 1595
					http.UpdateHttpMessage();
1234 dev 1596
					responsePos.NextOctetAndBack(); // go forward to see end of connection
1092 dev 1597
				}
1598
			}
1122 dev 1599
			catch(Exception ex)
1092 dev 1600
			{
1601
				Console.WriteLine(ex.Message + " (" + ex.GetType().Name + ")\n" + ex.StackTrace);
1602
			}
1603
		}
1604
 
1605
		private string GetToken(ParsePosition pos, int limit)
1606
		{
1607
			StringBuilder res = new StringBuilder(100);
1608
			int           len = 0;
1609
 
1233 dev 1610
			for(byte b = pos.NextOctet(); !pos.IsEnd && tokenChars[b]; b = pos.NextOctet())
1092 dev 1611
			{
1612
				res.Append(charValues[b]);
1613
				if(limit > 0 && limit < ++len) return null; // length limit
1614
			}
1233 dev 1615
			pos.Back();
1092 dev 1616
 
1617
			return res.ToString();
1618
		}
1619
 
1620
		private string GetUntilSpace(ParsePosition pos, int limit)
1621
		{
1622
			StringBuilder res = new StringBuilder(1024);
1623
			int           len = 0;
1624
 
1233 dev 1625
			for(byte b = pos.NextOctet(); !pos.IsEnd && b != 32 && b != 13 && b != 10; b = pos.NextOctet())
1092 dev 1626
			{                                     //     <space>    <cr>       <lf>
1627
				res.Append(charValues[b]);
1628
				if(limit > 0 && limit < ++len) return null; // length limit
1629
			}
1233 dev 1630
			pos.Back();
1092 dev 1631
 
1122 dev 1632
			return res.ToString();
1092 dev 1633
		}
1634
 
1635
		private string GetUntilEoL(ParsePosition pos, int limit)
1636
		{
1637
			StringBuilder res = new StringBuilder(1024);
1638
			int           len = 0;
1639
 
1233 dev 1640
			for(byte b = pos.NextOctet(); !pos.IsEnd && b != 13; b = pos.NextOctet())
1092 dev 1641
			{                                     //     <cr>
1642
				res.Append(charValues[b]);
1643
				if(limit > 0 && limit < ++len) return null; // length limit
1644
			}
1233 dev 1645
			pos.Back();
1092 dev 1646
 
1122 dev 1647
			return res.ToString();
1092 dev 1648
		}
1649
 
1650
		private void ExpectSpace(ParsePosition pos)
1651
		{
1233 dev 1652
			if(pos.IsEnd || pos.NextOctet() != 32)
1092 dev 1653
				throw new HttpParseException("Space expected");
1654
		}
1655
 
1656
		private void ExpectCRLF(ParsePosition pos)
1657
		{
1233 dev 1658
			if(pos.IsEnd || pos.NextOctet() != 13)
1092 dev 1659
				throw new HttpParseException("Carriage return expected");
1660
			if(pos.IsEnd || pos.NextOctet() != 10)
1661
				throw new HttpParseException("Linefeed expected");
1662
		}
1663
 
1664
		private void SkipEmptyLines(ParsePosition pos)
1665
		{
1233 dev 1666
			while(pos.NextOctetAndBack() == 13)
1667
			{
1092 dev 1668
				ExpectCRLF(pos);
1233 dev 1669
			}
1092 dev 1670
		}
1671
 
1672
		private void ParseRequestLine(ParsePosition pos, HttpMessage http)
1673
		{
1674
			// method
1234 dev 1675
			http.Request.Method = GetToken(pos, 1024);
1676
			if(http.Request.Method == null || http.Request.Method.Length == 0)
1092 dev 1677
				throw new HttpParseException("Request method name expected");
1678
			ExpectSpace(pos);
1679
 
1680
			// URI
1234 dev 1681
			http.Request.Uri = GetUntilSpace(pos, 1024);
1682
			if(http.Request.Uri == null || http.Request.Uri.Length == 0)
1092 dev 1683
				throw new HttpParseException("Request URI expected");
1684
 
1685
			if(pos.IsEnd)
1686
				throw new HttpParseException("Unexpected end of message");
1687
 
1688
			// EoL or version
1233 dev 1689
			byte b = pos.NextOctet();
1122 dev 1690
			if(b == 13)
1092 dev 1691
			{
1233 dev 1692
				pos.Back();
1693
				ExpectCRLF(pos);
1234 dev 1694
				http.Request.Version = HttpVersion.V0_9;
1092 dev 1695
			}
1122 dev 1696
			else if(b != 32)
1092 dev 1697
			{
1698
				throw new HttpParseException("HTTP version expected");
1699
			}
1700
 
1701
			// check version
1702
			string versionStr = GetUntilEoL(pos, 20);
1703
			if(pos.IsEnd || versionStr == null || versionStr.Length == 0)
1704
				throw new HttpParseException("HTTP version expected");
1705
 
1122 dev 1706
			if(versionStr == "HTTP/1.0")
1092 dev 1707
			{
1234 dev 1708
				http.Request.Version = HttpVersion.V1_0;
1092 dev 1709
			}
1122 dev 1710
			else if(versionStr == "HTTP/1.1")
1092 dev 1711
			{
1234 dev 1712
				http.Request.Version = HttpVersion.V1_1;
1092 dev 1713
			}
1122 dev 1714
			else
1092 dev 1715
			{
1716
				throw new HttpParseException("Unknown HTTP version: " + versionStr);
1717
			}
1718
 
1719
			ExpectCRLF(pos);
1720
		}
1721
 
1234 dev 1722
		private void ParseHeaders(ParsePosition pos, HttpMessage http, HttpHalfMessage half)
1092 dev 1723
		{
1724
			if(pos.IsEnd) return;  // end of TCP messages
1725
 
1122 dev 1726
			while(true)
1092 dev 1727
			{
1728
				if(pos.IsEnd)
1729
					throw new HttpParseException("Unexpected end of message");
1730
 
1233 dev 1731
				if(pos.NextOctetAndBack() == 13)
1092 dev 1732
				{
1233 dev 1733
					ExpectCRLF(pos);
1734
					return; // end of header, move to body
1092 dev 1735
				}
1736
				if(pos.IsEnd) return;  // end of TCP messages
1737
 
1738
				string name = GetToken(pos, 0);
1739
				if(name == null || name.Length == 0)
1234 dev 1740
					throw new HttpParseException("Header name expected");
1092 dev 1741
 
1233 dev 1742
				if(pos.IsEnd || pos.NextOctet() != 58)   // :
1234 dev 1743
					throw new HttpParseException("Header value expected");
1092 dev 1744
 
1745
				string s = TrimHeaderValue(GetUntilEoL(pos, 0));
1746
 
1747
				ExpectCRLF(pos);
1748
 
1234 dev 1749
				half.AddHeader(name, s);
1092 dev 1750
			}
1751
		}
1752
 
1753
		enum HeaderValueState
1754
		{
1755
			Space,
1756
			Token,
1757
			Quoted
1758
		}
1759
 
1760
		private string TrimHeaderValue(string s)
1761
		{
1762
			if(s == null) return null;
1763
 
1764
			HeaderValueState state = HeaderValueState.Space;
1765
			StringBuilder    buf   = new StringBuilder();
1766
 
1122 dev 1767
			for(int i = 0, l = s.Length; i < l; i++)
1092 dev 1768
			{
1769
				char c = s[i];
1122 dev 1770
				switch(state)
1092 dev 1771
				{
1772
					case HeaderValueState.Space:
1773
						if(c != ' ' && c != '\t')
1774
						{
1122 dev 1775
							if(c == '"')
1092 dev 1776
							{
1777
								if(buf.Length > 0) buf.Append(' ');
1778
								buf.Append(c);
1779
								state =	HeaderValueState.Quoted;
1780
							}
1122 dev 1781
							else
1092 dev 1782
							{
1783
								if(buf.Length > 0) buf.Append(' ');
1784
								buf.Append(c);
1785
								state =	HeaderValueState.Token;
1786
							}
1787
						}
1788
						break;
1789
 
1790
					case HeaderValueState.Token:
1122 dev 1791
						if(c == ' ' || c == '\t')
1092 dev 1792
						{
1793
							state =	HeaderValueState.Space;
1794
						}
1122 dev 1795
						else if(c == '"')
1092 dev 1796
						{
1797
							buf.Append(c);
1798
							state =	HeaderValueState.Quoted;
1799
						}
1122 dev 1800
						else
1092 dev 1801
						{
1802
							buf.Append(c);
1803
						}
1804
						break;
1805
 
1806
					case HeaderValueState.Quoted:
1122 dev 1807
						if(c == '"')
1092 dev 1808
						{
1809
							buf.Append(c);
1810
							i++;
1811
							if(i < l)
1122 dev 1812
							{
1092 dev 1813
								c = s[i];
1122 dev 1814
								if(c == ' ' || c == '\t')
1092 dev 1815
								{
1816
									state =	HeaderValueState.Space;
1817
								}
1122 dev 1818
								else if(c == '"')
1092 dev 1819
								{
1820
									buf.Append(c);
1821
									state =	HeaderValueState.Quoted;
1822
								}
1823
								else
1824
								{
1825
									buf.Append(c);
1826
									state =	HeaderValueState.Token;
1827
								}
1828
							}
1829
						}
1122 dev 1830
						else
1092 dev 1831
						{
1832
							buf.Append(c);
1833
						}
1834
						break;
1835
				}
1836
			}
1837
 
1838
			return buf.ToString();
1839
		}
1840
 
1233 dev 1841
		private HttpTransferEncoding ParseTransferEncoding(string encoding)
1092 dev 1842
		{
1233 dev 1843
			if(encoding == null) return HttpTransferEncoding.None;
1844
			encoding = encoding.ToLower();
1845
 
1846
			if(encoding == "identity")
1847
				return HttpTransferEncoding.Identity;
1848
			else if(encoding == "chunked")
1849
				return HttpTransferEncoding.Chunked;
1122 dev 1850
			else if(encoding == "gzip")
1233 dev 1851
				return HttpTransferEncoding.Gzip;
1122 dev 1852
			else if(encoding == "compress")
1233 dev 1853
				return HttpTransferEncoding.Compress;
1122 dev 1854
			else if(encoding == "deflate")
1233 dev 1855
				return HttpTransferEncoding.Deflate;
1122 dev 1856
			else
1233 dev 1857
				return HttpTransferEncoding.Unknown;
1092 dev 1858
		}
1859
 
1233 dev 1860
		private HttpContentEncoding ParseContentEncoding(string encoding)
1861
		{
1862
			if(encoding == null) return HttpContentEncoding.None;
1863
			encoding = encoding.ToLower();
1864
 
1865
			if(encoding == "identity")
1866
				return HttpContentEncoding.Identity;
1867
			else if(encoding == "gzip")
1868
				return HttpContentEncoding.Gzip;
1869
			else if(encoding == "compress")
1870
				return HttpContentEncoding.Compress;
1871
			else if(encoding == "deflate")
1872
				return HttpContentEncoding.Deflate;
1873
			else
1874
				return HttpContentEncoding.Unknown;
1875
		}
1876
 
1234 dev 1877
		private void SetHttpProperties(HttpMessage http, HttpHalfMessage half)
1092 dev 1878
		{
1879
			// length
1234 dev 1880
			HttpHeader contentLength = half.GetHeader("content-length");
1122 dev 1881
			if(contentLength != null)
1092 dev 1882
			{
1234 dev 1883
				half.Length = int.Parse(contentLength.Values[0]);
1092 dev 1884
			}
1885
 
1233 dev 1886
			// transfer encoding
1234 dev 1887
			HttpHeader transferEncoding = half.GetHeader("transfer-encoding");
1888
			half.TransferEncoding = ParseTransferEncoding((transferEncoding == null) ? null : transferEncoding.Values[0]);
1889
			if(HasBody(http, half) && half.TransferEncoding == HttpTransferEncoding.None)
1890
				half.TransferEncoding = HttpTransferEncoding.Identity;
1092 dev 1891
 
1233 dev 1892
			// content encoding
1234 dev 1893
			HttpHeader contentEncoding = half.GetHeader("content-encoding");
1894
			half.ContentEncoding = ParseContentEncoding((contentEncoding == null) ? null : contentEncoding.Values[0]);
1895
			if(HasBody(http, half) && half.ContentEncoding == HttpContentEncoding.None)
1896
				half.ContentEncoding = HttpContentEncoding.Identity;
1233 dev 1897
 
1092 dev 1898
			// type & charset
1234 dev 1899
			HttpHeader contentType = half.GetHeader("content-type");
1122 dev 1900
			if(contentType != null)
1092 dev 1901
			{
1234 dev 1902
				Match match = Regex.Match(contentType.Values[0], @"^\s*(\S+)/(\S+)\s*($|;\s*(charset=""?(\S+)""?)?)");
1122 dev 1903
				if(match.Success)
1092 dev 1904
				{
1234 dev 1905
					half.ContentType    = match.Groups[1].Captures[0].Value;
1906
					half.ContentSubtype = match.Groups[2].Captures[0].Value;
1907
					if(match.Groups.Count >= 6 && match.Groups[5].Captures.Count > 0)
1908
						half.Charset = match.Groups[5].Captures[0].Value.Trim('"');
1092 dev 1909
				}
1910
			}
1234 dev 1911
		}
1092 dev 1912
 
1234 dev 1913
		private void SetRequestProperties(HttpMessage http, HttpRequest request)
1914
		{
1915
			SetHttpProperties(http, request);
1916
 
1092 dev 1917
			// soap action
1234 dev 1918
			HttpHeader soapAction = request.GetHeader("soapaction");
1122 dev 1919
			if(soapAction != null)
1092 dev 1920
			{
1234 dev 1921
				request.SoapAction = soapAction.Values[0];
1092 dev 1922
			}
1923
		}
1924
 
1233 dev 1925
		// RFC 2616: 4.3
1234 dev 1926
		private bool HasBody(HttpMessage http, HttpHalfMessage half)
1092 dev 1927
		{
1234 dev 1928
			if(half.IsRequest)
1233 dev 1929
			{
1234 dev 1930
				return (http.Request.Length > 0) 
1931
					|| (http.Request.TransferEncoding != HttpTransferEncoding.None);
1233 dev 1932
			}
1933
			else 
1934
			{
1234 dev 1935
				if(http.Request.Method == "HEAD") return false;
1936
				if(http.Response.StatusCode <  200) return false;
1937
				if(http.Response.StatusCode == 204) return false;
1938
				if(http.Response.StatusCode == 304) return false;
1092 dev 1939
 
1233 dev 1940
				return true;
1941
			}
1942
		}
1943
 
1234 dev 1944
		private void ParseBody(ParsePosition pos, HttpMessage http, HttpHalfMessage half)
1233 dev 1945
		{
1234 dev 1946
			if(!HasBody(http, half)) return;
1233 dev 1947
 
1092 dev 1948
			// FIXME parse and save on-the-fly, dont wait util end of message
1949
 
1233 dev 1950
			byte[]               bin              = new byte[8*1024];
1951
			int                  len              = 0;   // current bin biffer length
1234 dev 1952
			int                  limit            = half.Length;
1233 dev 1953
			int                  chunkLen         = -1;  // current length of current chunk
1954
			int                  chunkLimit       = -1;
1234 dev 1955
			HttpTransferEncoding transferEncoding = half.TransferEncoding;
1956
			HttpContentEncoding  contentEncoding  = half.ContentEncoding;
1957
			string               contentType      = half.ContentType;
1958
			string               contentSubtype   = half.ContentSubtype;
1959
			string               charset          = half.Charset;
1092 dev 1960
 
1233 dev 1961
			for(byte b = pos.NextOctet(); !pos.IsEnd; b = pos.NextOctet())
1092 dev 1962
			{
1233 dev 1963
				// RFC 2616: 3.6.1
1964
				if(transferEncoding == HttpTransferEncoding.Chunked && chunkLimit < 0)
1965
				{
1966
					// FIXME recognize chunk-extension here
1967
 
1968
					// get chunk length
1969
					pos.Back();
1970
					string chunkLimitStr = GetUntilEoL(pos, 40);
1971
					if(pos.IsEnd || chunkLimitStr == null || chunkLimitStr.Length == 0)
1972
						throw new HttpParseException("Chunk length expected");
1973
 
1974
					try
1975
					{
1976
						chunkLimit = Convert.ToInt32(chunkLimitStr, 16);
1977
					}
1978
					catch(Exception)
1979
					{
1980
						throw new HttpParseException("Cannot parse chunk length");
1981
					}
1982
 
1983
					ExpectCRLF(pos);
1984
 
1985
					if(chunkLimit == 0) { // the end marker
1986
						ExpectCRLF(pos);
1987
						break;
1988
					}
1989
 
1990
					chunkLen = 0;
1991
					b        = pos.NextOctet();
1992
				}
1993
 
1994
				// grow array if full
1122 dev 1995
				if(len >= bin.Length)
1092 dev 1996
				{
1997
					byte[] newBin = new byte[bin.Length*2];
1998
					Array.Copy(bin, newBin, len);
1999
					bin = newBin;
2000
				}
2001
 
2002
				bin[len++] = b;
1233 dev 2003
				chunkLen++;
2004
				if(chunkLimit > 0)
1092 dev 2005
				{
1233 dev 2006
					if(chunkLen >= chunkLimit)  // full chunk
2007
					{
2008
						ExpectCRLF(pos);
2009
						chunkLimit = -1; // try to find length of next chunk on next iteration
2010
					}
1092 dev 2011
				}
1233 dev 2012
				else 
2013
				{
2014
					if(limit > 0 && len >= limit)  // full length
2015
					{
2016
						break;
2017
					}
2018
				}
1092 dev 2019
			}
1233 dev 2020
			if(transferEncoding == HttpTransferEncoding.Chunked && chunkLimit > 0 && chunkLen != chunkLimit)
2021
			{
2022
				throw new HttpParseException("Incomplete chunk found");
2023
			}
1092 dev 2024
 
1233 dev 2025
			// FIXME parse entity-headers for chunked encoding here
2026
 
1092 dev 2027
			string text = null;
1233 dev 2028
			if(contentEncoding == HttpContentEncoding.Identity && contentType == "text")
1092 dev 2029
			{
1122 dev 2030
				try
1092 dev 2031
				{
2032
					Encoding enc = Encoding.GetEncoding(charset == null ? (contentSubtype == "xml" ? "UTF-8" : "ASCII") : charset);
2033
					text = enc.GetString(bin, 0, len);
2034
				}
1122 dev 2035
				catch(NotSupportedException)
1092 dev 2036
				{
1233 dev 2037
					Console.WriteLine("Unsupported charset: " + charset);
1092 dev 2038
				}
2039
			}
2040
 
1234 dev 2041
			half.Length = len;
2042
			half.Body   = bin;
2043
			half.Text   = text;
2044
		}
2045
 
2046
		private void ParseResponse(ParsePosition pos, HttpMessage http)
2047
		{
2048
			ParseResponseLine(pos, http);
2049
			http.Response.StartTimestamp = pos.CurrentMessage.Timestamp;
2050
			http.UpdateHttpMessage();
2051
 
2052
			ParseHeaders(pos, http, http.Response);
2053
			SetHttpProperties(http, http.Response);
2054
			http.UpdateHttpMessage();
2055
 
2056
			ParseBody(pos, http, http.Response);
2057
			if("text" == http.Response.ContentType && "xml" == http.Response.ContentSubtype)
1092 dev 2058
			{
1234 dev 2059
				http.Response.Xml = new XmlMessage(http.Response.Text);
1092 dev 2060
			}
1234 dev 2061
			http.UpdateHttpMessage();
1092 dev 2062
		}
2063
 
2064
		private void ParseResponseLine(ParsePosition pos, HttpMessage http)
2065
		{
2066
			// version
2067
			string versionStr = GetUntilSpace(pos, 20);
2068
			if(pos.IsEnd || versionStr == null || versionStr.Length == 0)
2069
				throw new HttpParseException("HTTP version expected");
2070
 
1122 dev 2071
			if(versionStr == "HTTP/1.0")
1092 dev 2072
			{
1234 dev 2073
				http.Response.Version = HttpVersion.V1_0;
1092 dev 2074
			}
1122 dev 2075
			else if(versionStr == "HTTP/1.1")
1092 dev 2076
			{
1234 dev 2077
				http.Response.Version = HttpVersion.V1_1;
1092 dev 2078
			}
1122 dev 2079
			else
1092 dev 2080
			{
2081
				throw new HttpParseException("Unknown HTTP version: " + versionStr);
2082
			}
2083
			ExpectSpace(pos);
2084
 
2085
			// status code
2086
			string code = GetToken(pos, 3);
2087
			if(code == null || code.Length != 3)
2088
				throw new HttpParseException("Status code expected");
2089
 
1122 dev 2090
			try
1092 dev 2091
			{
2092
				int c = int.Parse(code);
2093
				if(c < 100 || c >= 1000) throw new HttpParseException("Status code expected");
1234 dev 2094
				http.Response.StatusCode = c;
1092 dev 2095
			}
1122 dev 2096
			catch(FormatException)
1092 dev 2097
			{
2098
				throw new HttpParseException("Status code expected");
2099
			}
2100
			ExpectSpace(pos);
2101
 
2102
			// status message
1234 dev 2103
			http.Response.StatusMessage = GetUntilEoL(pos, 0);
1122 dev 2104
 
1092 dev 2105
			if(pos.IsEnd)
2106
				throw new HttpParseException("Unexpected end of message");
2107
 
2108
			ExpectCRLF(pos);
2109
		}
2110
	}
2111
 
2112
	public class HttpHeader
2113
	{
2114
		private string   name;
2115
		private string[] headerValues;
2116
 
2117
		public string Name
2118
		{
2119
			get { return name; }
2120
		}
2121
 
2122
		public string[] Values
2123
		{
2124
			get { return headerValues; }
2125
		}
2126
 
2127
		internal HttpHeader()
2128
		{
2129
		}
2130
 
2131
		internal HttpHeader(string name, string headerValue)
2132
		{
2133
			this.name = name;
2134
			AddValue(headerValue);
2135
		}
2136
 
2137
		internal void AddValue(string value)
2138
		{
2139
			if(headerValues == null)
2140
			{
2141
				headerValues = new string[1];
2142
			}
1122 dev 2143
			else
1092 dev 2144
			{
2145
				string[] newValues = new string[headerValues.Length + 1];
2146
				Array.Copy(headerValues, 0, newValues, 0, headerValues.Length);
2147
				headerValues = newValues;
2148
			}
2149
 
2150
			headerValues[headerValues.Length-1] = value;
2151
		}
2152
	}
2153
 
1234 dev 2154
	public abstract class HttpHalfMessage
1092 dev 2155
	{
1234 dev 2156
		private   bool                 complete         = false;
2157
		private   HttpVersion          version;
2158
		protected LinkedList           headers          = new LinkedList();
2159
		protected Hashtable            headersHash      = new Hashtable();
2160
		private   int                  length           = -1; // -1 == unknown
2161
		private   HttpTransferEncoding transferEncoding = HttpTransferEncoding.None;
2162
		private   HttpContentEncoding  contentEncoding  = HttpContentEncoding.None;
2163
		private   string               contentType;
2164
		private   string               contentSubtype;
2165
		private   string               charset;
2166
		private   byte[]               body;
2167
		private   string               text;
2168
		private   XmlMessage           xml;
2169
		private   DateTime             startTimestamp   = DateTime.MinValue;
1092 dev 2170
 
1234 dev 2171
		public abstract bool IsRequest
1092 dev 2172
		{
1234 dev 2173
			get;
1092 dev 2174
		}
2175
 
1234 dev 2176
		public bool Complete
1092 dev 2177
		{
1234 dev 2178
			get { return complete; }
2179
			set { complete = value; }
1092 dev 2180
		}
2181
 
1234 dev 2182
		public HttpVersion Version
1092 dev 2183
		{
1234 dev 2184
			get { return version; }
2185
			set { version = value; }
1092 dev 2186
		}
2187
 
1234 dev 2188
		public LinkedList Headers
1092 dev 2189
		{
1234 dev 2190
			get { return headers; }
1092 dev 2191
		}
2192
 
1234 dev 2193
		public int Length
1092 dev 2194
		{
1234 dev 2195
			get { return length; }
2196
			set { length = value; }
1092 dev 2197
		}
2198
 
1234 dev 2199
		public HttpTransferEncoding TransferEncoding
1092 dev 2200
		{
1234 dev 2201
			get { return transferEncoding; }
2202
			set { transferEncoding = value; }
1092 dev 2203
		}
2204
 
1234 dev 2205
		public HttpContentEncoding ContentEncoding
1092 dev 2206
		{
1234 dev 2207
			get { return contentEncoding; }
2208
			set { contentEncoding = value; }
1092 dev 2209
		}
2210
 
1234 dev 2211
		public string ContentType
1092 dev 2212
		{
1234 dev 2213
			get { return contentType; }
2214
			set { contentType = value; }
1092 dev 2215
		}
2216
 
1234 dev 2217
		public string ContentSubtype
1233 dev 2218
		{
1234 dev 2219
			get { return contentSubtype; }
2220
			set { contentSubtype = value; }
1233 dev 2221
		}
2222
 
1234 dev 2223
		public string Charset
1092 dev 2224
		{
1234 dev 2225
			get { return charset; }
2226
			set { charset = value; }
1092 dev 2227
		}
2228
 
1234 dev 2229
		public byte[] Body
1092 dev 2230
		{
1234 dev 2231
			get { return body; }
2232
			set { body = value; }
1092 dev 2233
		}
2234
 
1234 dev 2235
		public string Text
1092 dev 2236
		{
1234 dev 2237
			get { return text; }
2238
			set { text = value; }
1092 dev 2239
		}
2240
 
1234 dev 2241
		public XmlMessage Xml
1092 dev 2242
		{
1234 dev 2243
			get { return xml; }
2244
			set { xml = value; }
1092 dev 2245
		}
2246
 
1234 dev 2247
        public DateTime StartTimestamp
1125 dev 2248
        {
1234 dev 2249
        	get { return startTimestamp; }
2250
        	set { startTimestamp = value; }
1125 dev 2251
        }
2252
 
1234 dev 2253
		public void AddHeader(string name, string headerValue)
1092 dev 2254
		{
1234 dev 2255
			HttpHeader header = (HttpHeader)headersHash[name];
2256
			if(header == null)
2257
			{
2258
				header = new HttpHeader(name, headerValue);
2259
				headers.Add(header);
2260
				headersHash.Add(name.ToLower(), header);
2261
			}
2262
			else
2263
			{
2264
				header.AddValue(headerValue);
2265
			}
1092 dev 2266
		}
2267
 
1234 dev 2268
		public HttpHeader GetHeader(string name)
1092 dev 2269
		{
1234 dev 2270
			return (HttpHeader)headersHash[name.ToLower()];
1092 dev 2271
		}
1234 dev 2272
	}
1092 dev 2273
 
1234 dev 2274
	public class HttpRequest : HttpHalfMessage
2275
	{
2276
		private string method;
2277
		private string uri;
2278
		private string soapAction;
1092 dev 2279
 
1234 dev 2280
		public override bool IsRequest
1092 dev 2281
		{
1234 dev 2282
			get { return true; }
1092 dev 2283
		}
2284
 
1234 dev 2285
		public string Method
1092 dev 2286
		{
1234 dev 2287
			get { return method; }
2288
			set { method = value; }
1092 dev 2289
		}
2290
 
1234 dev 2291
		public string Uri
1092 dev 2292
		{
1234 dev 2293
			get { return uri; }
2294
			set { uri = value; }
1092 dev 2295
		}
2296
 
1234 dev 2297
		public string SoapAction
1092 dev 2298
		{
1234 dev 2299
			get { return soapAction; }
2300
			set { soapAction = value; }
1092 dev 2301
		}
1234 dev 2302
	}
1092 dev 2303
 
1234 dev 2304
	public class HttpResponse : HttpHalfMessage
2305
	{
2306
		private int    statusCode;
2307
		private string statusMessage;
1092 dev 2308
 
1234 dev 2309
		public override bool IsRequest
1233 dev 2310
		{
1234 dev 2311
			get { return false; }
1233 dev 2312
		}
2313
 
1234 dev 2314
		public int StatusCode
1092 dev 2315
		{
1234 dev 2316
			get { return statusCode; }
2317
			set { statusCode = value; }
1092 dev 2318
		}
2319
 
1234 dev 2320
		public string StatusMessage
1092 dev 2321
		{
1234 dev 2322
			get { return statusMessage; }
2323
			set { statusMessage = value; }
1092 dev 2324
		}
1234 dev 2325
	}
1092 dev 2326
 
1234 dev 2327
	public class HttpMessage
2328
	{
2329
		private HttpRequest  request          = new HttpRequest();
2330
		private HttpResponse continueResponse = null;
2331
		private HttpResponse response         = new HttpResponse();
1092 dev 2332
 
1234 dev 2333
		public HttpRequest Request
1092 dev 2334
		{
1234 dev 2335
			get { return request; }
1092 dev 2336
		}
2337
 
1234 dev 2338
		public HttpResponse ContinueResponse
1092 dev 2339
		{
1234 dev 2340
			get { return continueResponse; }
1092 dev 2341
		}
2342
 
1234 dev 2343
		public HttpResponse Response
1092 dev 2344
		{
1234 dev 2345
			get { return response; }
1092 dev 2346
		}
2347
 
1235 dev 2348
        public override string ToString() // FIXME delete the method
2349
        {
2350
            return (request.SoapAction != null ? ("SOAP " + request.SoapAction)
2351
                : (request.Method == null ? "" : request.Method) + " " + (request.Uri == null ? "" : request.Uri));
2352
        }
2353
 
1092 dev 2354
		public event TcpEventHandler Update;
2355
 
2356
		protected virtual void OnUpdate(TcpEventArgs e)
2357
		{
1122 dev 2358
			if(Update != null)
1092 dev 2359
			{
1122 dev 2360
				Update(this, e);
1092 dev 2361
			}
2362
		}
2363
 
2364
		internal void UpdateHttpMessage()
2365
		{
2366
			OnUpdate(new TcpEventArgs());
2367
		}
1234 dev 2368
 
2369
		internal void GotContinueResponse()
2370
		{
2371
			continueResponse = response;
2372
			response = new HttpResponse();
2373
		}
1092 dev 2374
	}
2375
 
2376
	internal class HttpParseException : Exception
2377
	{
2378
		public HttpParseException() : base()
2379
		{
2380
		}
2381
 
2382
		public HttpParseException(string message) : base(message)
2383
		{
2384
		}
2385
 
2386
		public HttpParseException(System.Runtime.Serialization.SerializationInfo info,
2387
			System.Runtime.Serialization.StreamingContext context) : base(info, context)
2388
		{
2389
		}
2390
 
2391
		public HttpParseException(string message, Exception innerException) : base(message, innerException)
2392
		{
2393
		}
2394
	}
2395
 
2396
	public class XmlMessage
2397
	{
2398
		private XmlDocument xml;
2399
		private XmlException parseException;
2400
 
2401
		public XmlDocument Xml
2402
		{
2403
			get { return xml; }
2404
		}
2405
 
2406
		public XmlException ParseException
2407
		{
2408
			get { return parseException; }
2409
		}
2410
 
2411
		internal XmlMessage(string text)
2412
		{
1122 dev 2413
			try
1092 dev 2414
			{
2415
				this.xml = new XmlDocument();
2416
				this.xml.LoadXml(text);
2417
			}
2418
			catch(XmlException ex)
2419
			{
2420
				parseException = ex;
2421
			}
2422
		}
2423
	}
2424
 
2425
	public class TcpMessage
2426
	{
1199 dev 2427
		private TcpMessageDirection direction = TcpMessageDirection.None;
1092 dev 2428
		private byte[]              bytes;
2429
		private int                 length = 0;
2430
		private DateTime            timestamp;
2431
 
2432
		public TcpMessageDirection Direction
2433
		{
2434
			get { return direction; }
2435
			set { direction = value; }
2436
		}
2437
 
2438
		public int Length
2439
		{
2440
			get { return length; }
2441
		}
2442
 
2443
		public byte[] Bytes
2444
		{
1122 dev 2445
			get
1092 dev 2446
			{
2447
				return bytes;
2448
			}
2449
			set
2450
			{
2451
				length = 0;
2452
				Append(value);
2453
			}
2454
		}
2455
 
2456
		public DateTime Timestamp
2457
		{
2458
			get { return timestamp; }
2459
		}
2460
 
1199 dev 2461
		internal void SetTimestamp(DateTime timestamp)
2462
		{
2463
			this.timestamp = timestamp;
2464
		}
2465
 
1092 dev 2466
		internal TcpMessage()
2467
		{
2468
			this.timestamp = DateTime.Now;
2469
			this.bytes  = new byte[1024];
2470
		}
2471
 
2472
		internal TcpMessage(byte[] bytes, int length)
2473
		{
2474
			this.timestamp = DateTime.Now;
2475
			this.bytes     = new byte[length];
2476
			this.length   = length;
2477
			Array.Copy(this.bytes, bytes, length);
2478
		}
2479
 
2480
		internal TcpMessage Append(byte[] newBytes)
2481
		{
2482
			if(newBytes == null) return this;
2483
 
2484
			return Append(newBytes, newBytes.Length);
2485
		}
2486
 
2487
		internal TcpMessage Append(byte[] newBytes, int length)
2488
		{
2489
			if(newBytes == null) return this;
2490
 
1122 dev 2491
			lock(this)
1092 dev 2492
			{
2493
				// grow array
1122 dev 2494
				if(this.length + length > bytes.Length)
1092 dev 2495
				{
2496
					int newLength = bytes.Length;
2497
					while(this.length + length > newLength) newLength *= 2;
2498
					byte[] newArray = new byte[newLength];
2499
 
2500
					Array.Copy(bytes, newArray, this.length);
2501
					bytes = newArray;
2502
				}
2503
 
2504
				// store received bytes
2505
				Array.Copy(newBytes, 0, bytes, this.length, length);
2506
				this.length += length;
2507
 
2508
				return this;
2509
			}
2510
		}
2511
	}
2512
 
1232 dev 2513
	public class ThreadDebugger
2514
	{
2515
		private static ArrayList threads = new ArrayList();
2516
		private static ArrayList asyncs  = new ArrayList();
2517
 
2518
		internal static void Add(Thread thread, string comment)
2519
		{
2520
			threads.Add(new ThreadItem(thread, comment));
2521
			Console.WriteLine("ThreadDebugger: thread added {0}", comment);
2522
		}
2523
 
2524
		internal static void Add(IAsyncResult async, string comment)
2525
		{
2526
			asyncs.Add(new AsyncItem(async, comment));
2527
			Console.WriteLine("ThreadDebugger: async added ", comment);
2528
		}
2529
 
2530
		public static void PrintStatus()
2531
		{
2532
			Console.WriteLine("=== ThreadDebugger Status Begin ======");
2533
			Console.WriteLine("--- Threads --------------------------");
2534
			foreach(ThreadItem t in threads)
2535
			{
2536
				Console.WriteLine("{0} ({1}): {2}", t.thread.Name, t.comment, t.thread.IsAlive ? "alive" : "dead");
2537
			}
2538
			Console.WriteLine("--- Asyncs ---------------------------");
2539
			foreach(AsyncItem a in asyncs)
2540
			{
2541
				Console.WriteLine("{0}: {1}", a.comment, a.async.IsCompleted ? "alive" : "dead");
2542
			}
2543
			Console.WriteLine("=== ThreadDebugger Status End ========");
2544
		}
2545
 
2546
		private class ThreadItem
2547
		{
2548
			public Thread thread;
2549
			public string comment;
2550
 
2551
			public ThreadItem(Thread thread, string comment)
2552
			{
2553
				this.thread  = thread;
2554
				this.comment = comment;
2555
			}
2556
		}
2557
 
2558
		private class AsyncItem
2559
		{
2560
			public IAsyncResult async;
2561
			public string       comment;
2562
 
2563
			public AsyncItem(IAsyncResult async, string comment)
2564
			{
2565
				this.async   = async;
2566
				this.comment = comment;
2567
			}
2568
		}
2569
	}
1092 dev 2570
}