Subversion Repositories general

Rev

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