Fix value encoding to conform to spec.

Thanks to Marcelo Módolo <marcelo.rmodolo@gmail.com> for the heads up.
This commit is contained in:
Mahlon E. Smith 2021-04-04 15:56:16 -07:00
parent ac8c26f422
commit 833aab3000
2 changed files with 29 additions and 13 deletions

View file

@ -1,6 +1,6 @@
# vim: set et nosta sw=4 ts=4 ft=nim : # vim: set et nosta sw=4 ts=4 ft=nim :
# #
# Copyright (c) 2016-2019, Mahlon E. Smith <mahlon@martini.nu> # Copyright (c) 2016-2021, Mahlon E. Smith <mahlon@martini.nu>
# All rights reserved. # All rights reserved.
# Redistribution and use in source and binary forms, with or without # Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions are met: # modification, are permitted provided that the following conditions are met:
@ -102,6 +102,17 @@ type
proc printf( formatstr: cstring ) {.header: "<stdio.h>", varargs.} proc printf( formatstr: cstring ) {.header: "<stdio.h>", varargs.}
proc encode( str: string ): string =
## Encode value value strings per the "Value Encoding" section
## of the Stomp 1.2 spec.
result = str
result = result.
replace( "\r", "\\r" ).
replace( "\n", "\\n" ).
replace( "\\", "\\\\" ).
replace( ":", "\\c" )
#------------------------------------------------------------------- #-------------------------------------------------------------------
# R E S P O N S E # R E S P O N S E
#------------------------------------------------------------------- #-------------------------------------------------------------------
@ -270,7 +281,7 @@ proc newStompClient*( s: Socket, uri: string ): StompClient =
## .. code-block:: nim ## .. code-block:: nim
## ##
## var socket = newSocket() ## var socket = newSocket()
## var stomp = newStompClient( socket, "stomp://test:test@example.com/%2Fvhost" ) ## var stomp = newStompClient( socket, "stomp://test:test@example.com/vhost" )
## ##
## or if connecting with SSL, when compiled with -d:ssl: ## or if connecting with SSL, when compiled with -d:ssl:
## ##
@ -279,7 +290,7 @@ proc newStompClient*( s: Socket, uri: string ): StompClient =
## var socket = newSocket() ## var socket = newSocket()
## let sslContext = newContext( verifyMode = CVerifyNone ) ## let sslContext = newContext( verifyMode = CVerifyNone )
## sslContext.wrapSocket(socket) ## sslContext.wrapSocket(socket)
## var stomp = newStompClient( socket, "stomp+ssl://test:test@example.com/%2Fvhost" ) ## var stomp = newStompClient( socket, "stomp+ssl://test:test@example.com/vhost" )
## ##
let let
@ -327,7 +338,10 @@ proc newStompClient*( s: Socket, uri: string ): StompClient =
result.port = Port( port ) result.port = Port( port )
# Decode URI encoded slashes for vhosts. # Decode URI encoded slashes for vhosts.
result.vhost = result.vhost.replace( "%2f", "/" ).replace( "%2F", "/" ).replace( "//", "/" ) result.vhost = result.vhost.
replace( "%2f", "/" ).
replace( "%2F", "/" ).
replace( "//", "/" )
proc socksend( c: StompClient, data: string ): void = proc socksend( c: StompClient, data: string ): void =
@ -437,7 +451,7 @@ proc send*( c: StompClient,
if not c.connected: raise newException( StompError, "Client is not connected." ) if not c.connected: raise newException( StompError, "Client is not connected." )
c.socksend( "SEND" & CRLF ) c.socksend( "SEND" & CRLF )
c.socksend( "destination:" & destination & CRLF ) c.socksend( "destination:" & destination.encode & CRLF )
c.socksend( "content-length:" & $message.len & CRLF ) c.socksend( "content-length:" & $message.len & CRLF )
if not ( contenttype == "" ): c.socksend( "content-type:" & contenttype & CRLF ) if not ( contenttype == "" ): c.socksend( "content-type:" & contenttype & CRLF )
@ -447,7 +461,7 @@ proc send*( c: StompClient,
var txn_seen = false var txn_seen = false
for header in headers: for header in headers:
if header.name == "transaction": txn_seen = true if header.name == "transaction": txn_seen = true
c.socksend( header.name & ":" & header.value & CRLF ) c.socksend( header.name & ":" & header.value.encode & CRLF )
if not txn_seen: c.add_txn if not txn_seen: c.add_txn
if message == "": if message == "":
@ -473,7 +487,7 @@ proc subscribe*( c: StompClient,
if not c.connected: raise newException( StompError, "Client is not connected." ) if not c.connected: raise newException( StompError, "Client is not connected." )
c.socksend( "SUBSCRIBE" & CRLF ) c.socksend( "SUBSCRIBE" & CRLF )
c.socksend( "destination:" & destination & CRLF ) c.socksend( "destination:" & destination.encode & CRLF )
if id == "": if id == "":
c.socksend( "id:" & $c.subscriptions.len & CRLF ) c.socksend( "id:" & $c.subscriptions.len & CRLF )
@ -486,7 +500,7 @@ proc subscribe*( c: StompClient,
if ack != "auto": raise newException( StompError, "Unknown ack type: " & ack ) if ack != "auto": raise newException( StompError, "Unknown ack type: " & ack )
for header in headers: for header in headers:
c.socksend( header.name & ":" & header.value & CRLF ) c.socksend( header.name & ":" & header.value.encode & CRLF )
c.finmsg c.finmsg
c.subscriptions.add( destination ) c.subscriptions.add( destination )
@ -513,7 +527,7 @@ proc unsubscribe*( c: StompClient,
c.socksend( "UNSUBSCRIBE" & CRLF ) c.socksend( "UNSUBSCRIBE" & CRLF )
c.socksend( "id:" & $sub_id & CRLF ) c.socksend( "id:" & $sub_id & CRLF )
for header in headers: for header in headers:
c.socksend( header.name & ":" & header.value & CRLF ) c.socksend( header.name & ":" & header.value.encode & CRLF )
c.finmsg c.finmsg
c.subscriptions[ sub_id ] = "" c.subscriptions[ sub_id ] = ""
@ -707,7 +721,9 @@ You can also run a naive benchmark (deliveries/sec):
It will set messages to require acknowledgement, and nack everything, causing It will set messages to require acknowledgement, and nack everything, causing
a delivery loop for 10 seconds. a delivery loop for 10 seconds.
If your vhost requires slashes, use URI escaping: /%2Ftest
With older version of RabbitMQ, If your vhost requires slashes, you'll
need to URI escape: /%2Ftest
""" """
@ -751,8 +767,8 @@ If your vhost requires slashes, use URI escaping: /%2Ftest
of "RECEIPT": of "RECEIPT":
discard discard
of "MESSAGE": of "MESSAGE":
let body = r.payload discard r.payload
let id = r[ "ack" ] discard r[ "ack" ]
proc seen_heartbeat( c: StompClient, r: StompResponse ) = proc seen_heartbeat( c: StompClient, r: StompResponse ) =
heartbeats = heartbeats + 1 heartbeats = heartbeats + 1

View file

@ -1,7 +1,7 @@
# Package # Package
version = "0.1.1" version = "0.1.2"
author = "Mahlon E. Smith <mahlon@martini.nu>" author = "Mahlon E. Smith <mahlon@martini.nu>"
description = "A pure-nim implementation of the STOMP protocol for machine messaging." description = "A pure-nim implementation of the STOMP protocol for machine messaging."
license = "MIT" license = "MIT"