RabbitMQ Topic format - sub-topic under main topic - rabbitmq

When I am trying to push to topic in this format /topic/pushing/{organizationId} I am getting an error
messagingTemplate.convertAndSend("/topic/pushing/" + obj.getCustomerid(), obj);
The error:
15:06:48.901 [reactor-tcp-io-1] ERROR
o.s.m.s.s.StompBrokerRelayMessageHandler - Received ERROR
{message=[Invalid destination], content-type=[text/plain],
version=[1.0,1.1,1.2], content-length=[53]} session=system
text/plain payload='/pushing/2963_ent' is not a valid topic
destination
However when I change it to this format /topic/pushing.{organizationId}, replacing the slash with dot, it's working fine:
messagingTemplate.convertAndSend("/topic/pushing." + obj.getCustomerid(), obj);
Any idea how I can keep the slash / and have sub-topics under the main topic.

AMQP 0.9.1 specification has this to say about topic exchanges:
The topic exchange type works as follows:
1. A message queue binds to the exchange using a routing pattern, P.
2. A publisher sends the exchange a message with the routing key R.
3. The message is passed to the message queue if R matches P. The routing key used for a topic exchange MUST consist of zero or more
words delimited by dots. Each word may contain the letters A-Z and a-z
and digits 0-9.
The routing pattern follows the same rules as the routing key with the
addition that * matches a single word, and # matches zero or more
words. Thus the routing pattern *.stock.# matches the routing keys
usd.stock and eur.stock.db but not stock.nasdaq.
So "/" are not authorized in the routing key, and delimiter used is a dot.

Related

Redis PSUBSCRIBE Problems

A server is sending a message via Redis on a channel composed of some name and a unique id. I need to essentially find this channel and publish something back to it.
So far, I tried reading the documentation and experimenting with PSUBSCRIBE. However, the message that is received doesn't have the full channel name. It just has the pattern that I sent to PSUBSCRIBE. So, how can I go about finding the channel name?
I also included some code below if that would help understand my logic.
red = redis.StrictRedis(...)
pub = red.pubsub()
pub.psubscribe("name_pattern*")
for msg in pub.listen():
if msg["data"] == "...":
channel_name = msg["channel"]
red.publish(channel_name, "SOME MESSAGE")

Send data in an HTTP header and get it back

I am coding some test software to simulate something like a router. It will send URL requests on behalf of multiple users.
Is there any HTTP GET header field which I can send which the receiving server will always send back to me unchanged in the response so that I can associate the response with a user?
This is test software for use on a local LAN only, so I don't mind misusing a field, just as long as I get it returned unchanged.
according to http 1.1 rfc, response is:
Response = Status-Line ; Section 6.1
*(( general-header ; Section 4.5
| response-header ; Section 6.2
| entity-header ) CRLF) ; Section 7.1
CRLF
[ message-body ] ; Section 7.2
and here is notation:
*rule
The character "*" preceding an element indicates repetition. The
full form is "<n>*<m>element" indicating at least <n> and at most
<m> occurrences of element. Default values are 0 and infinity so
that "*(element)" allows any number, including zero; "1*element"
requires at least one; and "1*2element" allows one or two.
[rule]
Square brackets enclose optional elements; "[foo bar]" is
equivalent to "*1(foo bar)".
so, the only requirement for server is to respond with status code, other components are optional, always, which effectively means there is no requirement to send any header back
also, this contains list of all possible headers, none of them meet your requirements
I'm not sure about http 2.0, maybe somebody could add information about it

Weird characters in RabbitMQ queue names created by ServiceStack

I'm trying to add some custom logic to messages in ServiceStack and RabbitMQ.
It seems that the queues created by ServiceStack have some illegible characters prepended to the queue name and that makes it hard to reference them by name. For example (link from the RabbitMQ admin tool):
http://localhost:15672/#/queues/%2F/%E2%80%8E%E2%80%8Emq%3ATestRequest.inq
Note the %E2%80%8E%E2%80%8E prepended to the queue name. Although the queue looks like mq:TestRequest.inq it seems to have a different name. I also checked on another machine and the behaviour is consistent. I also suspect routing keys are affected in the same manner.
However, if I manually create a queue like this (and as far as I can see, ServiceStack does it in a similar way):
RabbitMqServer mqServer = new RabbitMqServer(connectionString: hostName, username: userName, password: password);
RabbitMqMessageFactory factory = (RabbitMqMessageFactory)MqServer.MessageFactory;
using (var mqClient = new RabbitMqProducer(factory))
{
var channel = mqClient.Channel;
string qName = new QueueNames(typeof(TestRequest)).In;
channel.QueueDeclare(qName, true, false, false, null);
}
The creted queue has a "normal" name without extra characters.
http://localhost:15672/#/queues/%2F/mq%3ATestRequest.inq
Also, it seems that the exchanges are created with names as expected.
My questions:
How to force ServiceStack to create queues without appending these characters?
OR
How to construct queue names containing these characters?
EDIT:
It seems that the inserted character is Left-to-right mark (‎ or \u200e). Prepending these characters to the queue name / routing key seems to get the job done. However, this looks rather hacky so I'd like to avoid doing this.
This might be inside the internals of RabbitMQ and may depend if you are using AMQP or STOMP. Here is an except from the full page:
If /, % or non-ascii bytes are in the queuename, exchange_name or routing_key, they are each replaced with the sequence %dd, where dd is the hexadecimal code for the byte.
RabbitMQ - Stomp - Destinations - AMQP Semantics

How to properly encode special characters in a REST API url

EDIT: The NHTSA docs, as CBroe points out, say to replace an ampersand with an underscore. However, I'm also getting an error with forward slashes (albeit a different one, page not found, because it's decoding the slash), for example the make 'EXISS/SOONER':
http://www.nhtsa.gov/webapi/api/Recalls/vehicle/modelyear/1997/make/EXISS%2FSOONER?format=json
And replacing the ampersand with an underscore no longer results in an error message, but in zero results returned, which should not be the case.
ORIGINAL POST:
I'm trying to download the content from the following URL:
http://www.nhtsa.gov/webapi/api/Recalls/vehicle/modelyear/1997/make/s&s?format=json
And the site returns the following error message:
Server Error in '/' Application.
A potentially dangerous Request.Path value was detected from the client (&).
The problem is the ampersand; a similar request for a different car make works:
http://www.nhtsa.gov/webapi/api/Recalls/vehicle/modelyear/1997/make/toyota?format=json
I have verified from a different endpoint that S&S is a valid make for the API.
Based on stackoverflow answers, I've tried all the following without success:
http://www.nhtsa.gov/webapi/api/Recalls/vehicle/modelyear/1997/make/s%26s?format=json
http://www.nhtsa.gov/webapi/api/Recalls/vehicle/modelyear/1997/make/s%26amp;s?format=json
http://www.nhtsa.gov/webapi/api/Recalls/vehicle/modelyear/1997/make/s%26amp%3Bs?format=json

RabbitMQ Header Exchange using a "NOT" or "Didn't fit anyone else go here"

I've been learning RabbitMQ the last couple weeks. I'm trying to setup a desicision tree type routing using a "Header" Exchange. I know how to brach it out if it matches. But I want a "catch all" queue that's only sent to if the header didn't match anything else in the tree.
So
Exchange1 -> if header.value1 = "company1" then goto queue "company1"
-> if header.value1 = "company2" then goto queue "company2"
-> if header.value1 didn't match anyone else then goto queue "catch all"
I got the first two easily figured out. But I can't figure out how to do a "not" or "didn't find a match".
If just set up a "catch all" without any rules associated with it, then ALL messages are sent there, including the ones that do find matches under the other rules.
There is no NOT capabilities in the RabbitMQ bindings. However, RabbitMQ provides a feature to do what you are looking for which is called Alternate Exchange.
You need to set a policy in the exchange to send the message to an alternative exchange and you will need to bind another queue (for you would be "catch all"). This new exchange will just get the messages that couldn't be routed before so it can be created as fanout.
You can find more information here: Alternate Exchanges