public void ToArray_with_xml_body()
		{
			const string someXml = "<message>hello world</message>";
			byte[] payload = Encoding.UTF8.GetBytes(someXml);
			MemoryStream body = new MemoryStream(payload);

			var frame = new StompFrame
			            	{
			            		Command = "SEND",
			            		Headers = new StompHeaderCollection
			            		          	{
			            		          		{"content-type", "application/xml; encoding=UTF8"},
			            		          	},
			            		Body = body,
			            	};

			var bytes = frame.ToArray();

			var text = new StreamReader(new MemoryStream(bytes), Encoding.UTF8).ReadToEnd();

			string expectedText = "SEND\r\n"
			                      + "content-type:application/xml; encoding=UTF8\r\n"
			                      + "content-length:" + payload.Length + "\r\n\r\n"
			                      + someXml
			                      + "\0";
			Assert.AreEqual(expectedText, text);
		}
		public void ToArray_with_empty_body()
		{
			var frame = new StompFrame
			            	{
			            		Command = "CONNECT",
			            		Headers = new StompHeaderCollection
			            		          	{
			            		          		{"login", "scott"},
			            		          		{"passcode", "tiger"},
			            		          	},
			            		Body = null,
			            	};

			var bytes = frame.ToArray();

			var text = new StreamReader(new MemoryStream(bytes), Encoding.UTF8).ReadToEnd();

			const string expectedText = "CONNECT\r\nlogin:scott\r\npasscode:tiger\r\ncontent-length:0\r\n\r\n\0";
			Assert.AreEqual(expectedText, text);
		}
		public void Subscribe()
		{
			using (_lock.Lock())
			{
				if (State == StompSubscriptionState.Unsubscribed)
				{
					var message = new StompFrame(StompCommand.Subscribe)
					              	{
					              		Headers =
					              			{
					              				{StompHeader.Id, _subscriptionIdText},
					              				{StompHeader.Destination, Destination},
					              				{StompHeader.Ack, Ack},
					              			}
					              	};
					_lock.AfterUnlock(RaiseStateChanged);
					State = StompSubscriptionState.Subscribing;
					Client.SendRawMessage(message, true);
				}
			}
		}
		public void Receive_small_frame_in_one_receive()
		{
			const string payloadText = "<message>This is a message</message>";
			byte[] payloadBytes = Encoding.UTF8.GetBytes(payloadText);
			MemoryStream memoryStream = new MemoryStream(payloadBytes);

			var originalFrame = new StompFrame
			                    	{
			                    		Command = "SEND",
			                    		Headers =
			                    			{
			                    				{"destination", "/queue/a"},
			                    				{"transaction", "tx-112"},
			                    			},
			                    		Body = memoryStream,
			                    	};

			byte[] data = originalFrame.ToArray();

			var builder = new StompFrameBuilder();
			builder.ReceiveBytes(data, 0, data.Length);

			Assert.IsTrue(builder.IsFrameReady, "Unexpected result");

			var receivedFrame = builder.GetNextFrame();
			Assert.IsNotNull(receivedFrame);
			Assert.IsNull(builder.GetNextFrame());

			Assert.AreEqual(originalFrame.Command, receivedFrame.Command);
			Assert.AreEqual(originalFrame.Headers["destination"], receivedFrame.Headers["destination"]);
			Assert.AreEqual(originalFrame.Headers["transaction"], receivedFrame.Headers["transaction"]);
			Assert.AreEqual(originalFrame.Headers["content-length"], receivedFrame.Headers["content-length"]);
			Assert.AreEqual(originalFrame.Headers.Count, receivedFrame.Headers.Count);
			Assert.AreEqual(payloadBytes.Length, receivedFrame.Body.Length);

			string receivedText = Encoding.UTF8.GetString(receivedFrame.Body.ToArray());
			Assert.AreEqual(payloadText, receivedText);
		}
		public StompMessageEventArgs(StompFrame message)
		{
			Message = Verify.ArgumentNotNull(message, "message");
		}
		public void Dispose()
		{
			using (_lock.Lock())
			{
				var oldState = State;
				if (!IsDisposed())
				{
					State = StompSubscriptionState.Disposed;
					_lock.AfterUnlock(RaiseStateChanged);
					if (oldState == StompSubscriptionState.Subscribing || oldState == StompSubscriptionState.Subscribed)
					{
						var message = new StompFrame(StompCommand.Unsubscribe)
						              	{
						              		Headers =
						              			{
						              				{StompHeader.Id, _subscriptionIdText}
						              			}
						              	};
						Client.SendRawMessage(message, false);
					}
				}
			}
			MessageArrived = null;
			StateChanged = null;
		}
Example #7
0
		private void CheckConnected()
		{
			using (Lock.Lock())
			{
				if (!_isDisposed)
				{
					if (_connected)
					{
						if (_transport == null || !_transport.Connected)
						{
							_connected = false;
							Log.Debug("Client is now disconnected from server");
							Lock.AfterUnlock(() => OnConnectedChanged(EventArgs.Empty));
						}
						StopOutgoingHeartBeatTimer();
						StopIncomingHeartBeatTimer();
						StopConnectTimer();
					}
					else
					{
						if (_transport != null && _transport.Connected && !_waitingForConnectedFrame)
						{
							var login = Login ?? string.Empty;
							var passcode = Passcode ?? string.Empty;

							// the client id provides some help with diagnostics by identifying the client process
							var processName = Path.GetFileNameWithoutExtension(Process.GetCurrentProcess().MainModule.FileName);
							var clientId = Environment.MachineName
							               + "/" + processName
							               + "/" + Process.GetCurrentProcess().Id;

							_sentHeartBeatValues = new HeartBeatValues(OutgoingHeartBeat, IncomingHeartBeat);

							// time to send a CONNECT message
							var frame = new StompFrame {
							                           	Command = StompCommand.Connect,
							                           	Headers = {
							                           	          	{StompHeader.Login, login},
							                           	          	{StompHeader.Passcode, passcode},
							                           	          	{StompHeader.HeartBeat, _sentHeartBeatValues.ToString()},
							                           	          	{StompHeader.NonStandard.ClientId, clientId}
							                           	          }
							                           };

							// a little enhancement, if we are re-connecting a previous session,
							// include the session id so that we can resume
							if (_sessionId != null)
							{
								frame.Headers[StompHeader.Session] = _sessionId;
							}

							_waitingForConnectedFrame = true;
							StartConnectTimer();
							_transport.SendFrame(frame);
							Log.Debug("Sent " + frame.Command + " command to server");
						}
					}
				}
			}
		}
		public void Missing_header_results_in_null_value()
		{
			var message = new StompFrame();
			Assert.IsNull(message.Headers["missing-header"]);
		}
		public void ToString_with_xml_body()
		{
			var frame = new StompFrame
			{
				Command = "MESSAGE",
				Headers = new StompHeaderCollection
			            		          	{
			            		          		{"subscription", "1"},
			            		          		{"content-length", "123"},
												{"content-type", "application/xml"},
												{"clr-type", "Test.Type,Test"},
												{"message-id", "6"},
			            		          	},
				Body = new MemoryStream(),
			};

			var writer = new StreamWriter(frame.Body);
			writer.WriteLine("<?xml version='1.0'>");
			writer.WriteLine("<Test>");
			writer.WriteLine("    <Name>This is the name</Name>");
			writer.WriteLine("</Test>");
			writer.Flush();

			frame.Headers["content-length"] = frame.Body.Length.ToString(CultureInfo.InvariantCulture);

			var actual = frame.ToString();
			const string expected = "MESSAGE message-id:6 subscription:1 content-length:74 clr-type:Test.Type,Test "
			                        + "<?xml version='1.0'> <Test> <Name>This is the name</Name> </Test>";
			Assert.AreEqual(expected, actual);
		}
		public void Expires_header()
		{
			var frame = new StompFrame();
			var dateTime = new DateTimeOffset(2099, 11, 10, 19, 18, 17, 16, TimeSpan.FromHours(10));

			frame.SetExpires(dateTime);
			Assert.AreEqual("20991110T091817Z", frame.Headers[StompHeader.NonStandard.Expires]);

			// truncated milliseconds means not expired
			Assert.IsFalse(frame.IsExpiredAt(dateTime - TimeSpan.FromSeconds(1)));

			Assert.IsTrue(frame.IsExpiredAt(dateTime + TimeSpan.FromSeconds(1)));
		}
		public void Cannot_deserialize_without_content_type()
		{
			var s1 = new SerializeTestClass
			{
				Number = 123,
				Text = "This is some text"
			};

			var frame = new StompFrame();
			frame.Serialize(s1);
			frame.Headers[StompHeader.ContentType] = "text/plain";

			try
			{
				frame.Deserialize();
				Assert.Fail("Expected exception");
			}
			catch (InvalidOperationException ex)
			{
				Assert.AreEqual("Cannot deserialize: content-type:text/plain", ex.Message);
			}
		}
		public void Header_value_contains_colon()
		{
			var originalFrame = new StompFrame
			                    	{
			                    		Command = "SEND",
			                    		Headers =
			                    			{
			                    				{"destination", "queue://this-contains:three:colons"},
			                    			},
			                    	};

			byte[] data = originalFrame.ToArray();
			var builder = new StompFrameBuilder();
			builder.ReceiveBytes(data, 0, data.Length);
			var receivedFrame = builder.GetNextFrame();
			Assert.IsNotNull(receivedFrame);
			Assert.AreEqual(originalFrame.Headers["destination"], receivedFrame.Headers["destination"]);
			Assert.AreEqual("queue://this-contains:three:colons", receivedFrame.Headers["destination"]);
		}
Example #13
0
		private void AssignSessionAndResubscribe(StompFrame frame)
		{
			var oldSessionId = _sessionId;
			_sessionId = frame.Headers[StompHeader.Session];
			if (oldSessionId != _sessionId && _subscriptions.Count > 0)
			{
				// This is where we had an old session, but lost it. The most probable
				// cause is that the server was stopped and restarted. What we do here
				// is re-send our subscription information.
				foreach (var subscription in _subscriptions.Values)
				{
					Log.DebugFormat("Resubscribing subscription {0}: {1}", subscription.SubscriptionId, subscription.Destination);
					subscription.Subscribe();
				}
			}
		}
Example #14
0
		private void HandleReceipt(StompFrame message)
		{
			var receiptIdText = message.Headers[StompHeader.ReceiptId];
			if (Log.IsDebugEnabled)
			{
				Log.DebugFormat("{0} received, {1}={2}", message.Command, StompHeader.ReceiptId, receiptIdText);
			}
			if (receiptIdText == null)
			{
				// TODO: what do we do here, disconnect?
				Log.ErrorFormat("Missing {0} header in {1} command", StompHeader.ReceiptId, message.Command);
				_transport.Shutdown();
				return;
			}

			long receiptId;
			if (!long.TryParse(receiptIdText, out receiptId))
			{
				// TODO: what to we do here, disconnect?
				Log.ErrorFormat("Invalid value for {0} header: {1}", StompHeader.ReceiptId, receiptIdText);
				_transport.Shutdown();
				return;
			}

			if (_pendingSendMessages.Count == 0)
			{
				Log.ErrorFormat("Received RECEIPT {0} but nothing asked for it", receiptId);
				_transport.Shutdown();
				return;
			}

			var sentMessage = _pendingSendMessages.Peek();
			var idText = sentMessage.Headers[StompHeader.Receipt];
			if (idText == null)
			{
				Log.ErrorFormat("Received RECEIPT {0} but nothing asked for it (and there is a message queued)",
				                receiptId);
				_transport.Shutdown();
				return;
			}

			// the current implementation never sends more than one message requiring receipt without receiving a receipt
			var id = long.Parse(sentMessage.Headers[StompHeader.Receipt]);
			if (id != receiptId)
			{
				Log.ErrorFormat("Received RECEIPT {0} but expected RECEIPT {1}", id, receiptId);
				_transport.Shutdown();
			}

			_pendingSendMessages.Dequeue();
			_sendInProgress = false;

			if (sentMessage.Command == StompCommand.Subscribe)
			{
				int subscriptionId = int.Parse(sentMessage.Headers[StompHeader.Id]);
				StompSubscription subscription;
				if (_subscriptions.TryGetValue(subscriptionId, out subscription))
				{
					subscription.Confirm();
				}
			}

			SendNextMessage();
		}
Example #15
0
		private void HandleError(StompFrame message)
		{
			var messageText = message.Headers[StompHeader.Message];
			if (messageText.StartsWith(ErrorMessages.SessionDoesNotExistPrefix) && !_connected)
			{
				// We have tried to reconnect to our old session, but it no longer exists, so remove it.
				Log.Info("Server says our session no longer exists. Will ask for a new one");
				_sessionId = null;
				foreach (var subscription in _subscriptions.Values)
				{
					subscription.SubscriptionLost();
				}
			}
		}
Example #16
0
		private StompSubscription HandleMessage(StompFrame message)
		{
			var subscriptionIdText = message.Headers[StompHeader.Subscription];
			if (subscriptionIdText == null)
			{
				Log.WarnFormat("Received {0} message without a {1} header", message.Command, StompHeader.Subscription);
				return null;
			}

			int subscriptionId;
			if (!int.TryParse(subscriptionIdText, out subscriptionId))
			{
				Log.WarnFormat("Received {0} message with invalid {1}: {2}", message.Command, StompHeader.Subscription,
				               subscriptionIdText);
				return null;
			}

			StompSubscription subscription;
			if (!_subscriptions.TryGetValue(subscriptionId, out subscription))
			{
				Log.WarnFormat("Receive {0} message with unknown {1}: {2}",
				               message.Command,
				               StompHeader.Subscription,
				               subscriptionId);
				return null;
			}

			return subscription;
		}
Example #17
0
		private void HandleConnected(StompFrame frame)
		{
			AssignSessionAndResubscribe(frame);
			StopConnectTimer();
			_connected = true;
			_waitingForConnectedFrame = false;
			Log.DebugFormat("Received {0} response, {1}={2}", frame.Command, StompHeader.Session, _sessionId);

			var serverHeartBeatValues = new HeartBeatValues(frame.Headers[StompHeader.HeartBeat]);
			_negotiatedHeartBeatValues = _sentHeartBeatValues.CombineWith(serverHeartBeatValues);

			StartIncomingHeartBeatTimer();
			StartOutgoingHeartBeatTimer();
			SendNextMessage();
		}
		public void BodyText_tests()
		{
			var frame = new StompFrame
			            	{
			            		Command = "COMMAND",
			            		BodyText = "1",
			            	};

			Assert.AreEqual("1", frame.BodyText);
		}
		public void Serialize()
		{
			var s1 = new SerializeTestClass
			         	{
			         		Number = 123,
			         		Text = "This is some text"
			         	};

			var frame = new StompFrame();
			frame.Serialize(s1);

			var s2 = (SerializeTestClass)frame.Deserialize();
			Assert.IsNotNull(s2);
			Assert.AreEqual(s1.Number, s2.Number);
			Assert.AreEqual(s1.Text, s2.Text);
		}
		public void Receive_two_frames_in_one_receive()
		{
			const string payloadText = "<message>This is a message</message>";
			byte[] payloadBytes = Encoding.UTF8.GetBytes(payloadText);
			MemoryStream memoryStream = new MemoryStream(payloadBytes);

			var originalFrame = new StompFrame
			                    	{
			                    		Command = "SEND",
			                    		Headers =
			                    			{
			                    				{"destination", "/queue/a"},
			                    				{"transaction", "tx-112"},
			                    			},
			                    		Body = memoryStream,
			                    	};

			byte[] data1 = originalFrame.ToArray();

			originalFrame.Headers["destination"] = "/queue/b";
			originalFrame.Headers["transaction"] = "tx-113";

			byte[] data2 = originalFrame.ToArray();

			byte[] combinedData = new byte[data1.Length + data2.Length];
			Array.Copy(data1, combinedData, data1.Length);
			Array.Copy(data2, 0, combinedData, data1.Length, data2.Length);

			var builder = new StompFrameBuilder();

			builder.ReceiveBytes(combinedData, 0, combinedData.Length);
			Assert.IsTrue(builder.IsFrameReady);

			var receivedFrame1 = builder.GetNextFrame();
			Assert.IsNotNull(receivedFrame1);
			var receivedFrame2 = builder.GetNextFrame();
			Assert.IsNotNull(receivedFrame2);
			Assert.IsNull(builder.GetNextFrame());

			Assert.AreEqual(originalFrame.Command, receivedFrame1.Command);
			Assert.AreEqual("/queue/a", receivedFrame1.Headers["destination"]);
			Assert.AreEqual("tx-112", receivedFrame1.Headers["transaction"]);
			Assert.AreEqual(originalFrame.Headers.Count, receivedFrame1.Headers.Count);
			Assert.AreEqual(payloadBytes.Length, receivedFrame1.Body.Length);
			Assert.AreEqual(payloadText, Encoding.UTF8.GetString(receivedFrame1.Body.ToArray()));

			Assert.AreEqual(originalFrame.Command, receivedFrame2.Command);
			Assert.AreEqual("/queue/b", receivedFrame2.Headers["destination"]);
			Assert.AreEqual("tx-113", receivedFrame2.Headers["transaction"]);
			Assert.AreEqual(originalFrame.Headers.Count, receivedFrame2.Headers.Count);
			Assert.AreEqual(payloadBytes.Length, receivedFrame2.Body.Length);
			Assert.AreEqual(payloadText, Encoding.UTF8.GetString(receivedFrame2.Body.ToArray()));
		}
		public void Cannot_deserialize_without_clr_type()
		{
			var s1 = new SerializeTestClass
			{
				Number = 123,
				Text = "This is some text"
			};

			var frame = new StompFrame();
			frame.Serialize(s1);
			frame.Headers[StompHeader.NonStandard.ClrType] = null;

			try
			{
				frame.Deserialize();
				Assert.Fail("Expected exception");
			}
			catch (InvalidOperationException ex)
			{
				Assert.AreEqual("Cannot deserialize: no clr-type specified", ex.Message);
			}
		}
		internal void ReceiveMessage(StompFrame message)
		{
			using (_lock.Lock())
			{
				if (IsDisposed())
				{
					// Silently discard messages received after being disposed.
					// By not acknowledging them, they will not be discarded by the server
					return;
				}

				var messageId = message.Headers[StompHeader.MessageId];

				if (messageId == null)
				{
					Log.Warn("Received message from server without a " + StompHeader.MessageId + " header");
				}
				else
				{
					if (Ack != StompAck.Auto)
					{
						var ackMessage = new StompFrame(StompCommand.Ack)
						                 	{
						                 		Headers =
						                 			{
						                 				{StompHeader.Subscription, _subscriptionIdText},
						                 				{StompHeader.MessageId, messageId},
						                 			}
						                 	};
						Client.SendRawMessage(ackMessage, false);
					}
				}
			}

			RaiseMessageArrived(message);
		}
		public void KeepAlive_frame()
		{
			var frame = new StompFrame(string.Empty);
			Assert.IsTrue(frame.IsHeartBeat);
			frame.Command = null;
			Assert.IsTrue(frame.IsHeartBeat);
			frame.Command = "XXX";
			Assert.IsFalse(frame.IsHeartBeat);
		}
Example #24
0
		public void SendMessage(StompFrame message)
		{
			Verify.ArgumentNotNull(message, "message");
			CheckDisposed();

			if (message.Command == null)
			{
				message.Command = StompCommand.Send;
			}
			else if (message.Command != StompCommand.Send)
			{
				throw new InvalidOperationException("Only " + StompCommand.Send + " commmands permitted");
			}

			if (message.Headers[StompHeader.Destination] == null)
			{
				throw new InvalidOperationException(("Header mising: " + StompHeader.Destination));
			}
			SendRawMessage(message, false);
		}
		public void ToString_with_large_text_body()
		{
			var frame = new StompFrame
			{
				Command = "MESSAGE",
				Headers = new StompHeaderCollection
			            		          	{
			            		          		{"subscription", "1"},
			            		          		{"content-length", "123"},
												{"content-type", "text/plain"},
												{"message-id", "6"},
			            		          	},
				Body = new MemoryStream(),
			};

			var writer = new StreamWriter(frame.Body);
			writer.WriteLine("12345678901234567890123456789012345678901234567890");
			writer.WriteLine("12345678901234567890123456789012345678901234567890");
			writer.WriteLine("12345678901234567890123456789012345678901234567890");
			writer.WriteLine("12345678901234567890123456789012345678901234567890");
			writer.WriteLine("12345678901234567890123456789012345678901234567890");
			writer.WriteLine("12345678901234567890123456789012345678901234567890");
			writer.WriteLine("12345678901234567890123456789012345678901234567890");
			writer.WriteLine("12345678901234567890123456789012345678901234567890");
			writer.WriteLine("12345678901234567890123456789012345678901234567890");
			writer.WriteLine("12345678901234567890123456789012345678901234567890");
			writer.Flush();

			frame.Headers["content-length"] = frame.Body.Length.ToString(CultureInfo.InvariantCulture);

			var actual = frame.ToString();
			const string expected = "MESSAGE message-id:6 subscription:1 content-length:520 "
			                        + "12345678901234567890123456789012345678901234567890 "
			                        + "12345678901234567890123456789012345678901234567890 "
									+ "12345678901234567890123456789012345678901234567890 "
									+ "12345678901234567890123456789012345678901234567890 "
									+ "12345678901234567890123456789012345678901234567890 "
									+ "12345678901234567890123456789012345678901234567890 "
									+ "12345678901234567890123456789012345678901234...";
			Assert.AreEqual(expected, actual);
		}
Example #26
0
		internal void SendRawMessage(StompFrame message, bool receiptRequired)
		{
			using (Lock.Lock())
			{
				if (!_isDisposed)
				{
					if (receiptRequired)
					{
						_receiptId += 1;
						message.Headers[StompHeader.Receipt] = _receiptId.ToString();
					}
					_pendingSendMessages.Enqueue(message);
					SendNextMessage();
				}
			}
		}
		private void RaiseMessageArrived(StompFrame frame)
		{
			if (MessageArrived != null)
			{
				var args = new StompMessageEventArgs(frame);
				var synchronizationContext = SynchronizationContext;
				if (synchronizationContext == null)
				{
					MessageArrived(this, args);
				}
				else
				{
					SendOrPostCallback callback = (obj => MessageArrived(this, args));
					synchronizationContext.Send(callback, null);
				}
			}
		}
Example #28
0
		public void SendTextMessage(string destination, string text)
		{
			Verify.ArgumentNotNull(destination, "destination");
			Verify.ArgumentNotNull(text, "text");
			CheckDisposed();
			var frame = new StompFrame(StompCommand.Send) {
			                                              	Headers = {
			                                              	          	{StompHeader.Destination, destination},
			                                              	          	{StompHeader.ContentType, "text/plain"}
			                                              	          },
			                                              	BodyText = text
			                                              };
			SendRawMessage(frame, false);
		}
		public void Null_command_results_in_heartbeat()
		{
			var data = new StompFrame { Command = null }.ToArray();
			Assert.AreEqual(1, data.Length);
			Assert.AreEqual(10, data[0]);
		}
		void ClientConnectedChanged(object sender, EventArgs e)
		{
			if (_clientTransport.Connected)
			{
				Log.Debug("Client: connected to server");
				const string text = "1";
				var frame = new StompFrame
				            	{
				            		Command = StompCommand.Message,
				            		BodyText = text,
				            	};
				_clientTransport.SendFrame(frame);
				Log.Debug("Client: sent message: " + text);
			}
			else
			{
				Log.Debug("Client: disconnected from server");
			}
		}