Subversion Repositories general

Rev

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