Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Newer
Older
100644 197 lines (178 sloc) 6.58 kb
45fd176 Elias Karakoulakis - added static+dynamic lib target in Makefile
authored
1 /*
2 BoostStomp - a STOMP (Simple Text Oriented Messaging Protocol) client
3 ----------------------------------------------------
4 Copyright (c) 2012 Elias Karakoulakis <elias.karakoulakis@gmail.com>
5
6 SOFTWARE NOTICE AND LICENSE
7
8 BoostStomp is free software: you can redistribute it and/or modify
9 it under the terms of the GNU Lesser General Public License as published
10 by the Free Software Foundation, either version 3 of the License,
11 or (at your option) any later version.
12
13 BoostStomp is distributed in the hope that it will be useful,
14 but WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 GNU Lesser General Public License for more details.
17
18 You should have received a copy of the GNU Lesser General Public License
19 along with BoostStomp. If not, see <http://www.gnu.org/licenses/>.
20
21 for more information on the LGPL, see:
22 http://en.wikipedia.org/wiki/GNU_Lesser_General_Public_License
23 */
24
c473992 Elias Karakoulakis - initial support for reconnection
authored
25 #include <boost/format.hpp>
0389cbd Elias Karakoulakis removed boost::xpressive along with some ~5mb of needless binary blurb, ...
authored
26 #include <boost/lexical_cast.hpp>
27 #include "BoostStomp.hpp"
28 #include "helpers.h"
c473992 Elias Karakoulakis - initial support for reconnection
authored
29
45fd176 Elias Karakoulakis - added static+dynamic lib target in Makefile
authored
30 namespace STOMP {
c473992 Elias Karakoulakis - initial support for reconnection
authored
31
32 using namespace boost;
7b0a3cd Elias Karakoulakis - valgrind has revealed subtle thread sync bugs. Fixed.
authored
33 using namespace boost::asio;
c473992 Elias Karakoulakis - initial support for reconnection
authored
34
45fd176 Elias Karakoulakis - added static+dynamic lib target in Makefile
authored
35 /*
36 * Escaping is needed to allow header keys and values to contain those frame header
37 * delimiting octets as values. The CONNECT and CONNECTED frames do not escape the
38 * colon or newline octets in order to remain backward compatible with STOMP 1.0.
39 * C style string literal escapes are used to encode any colons and newlines that
40 * are found within the UTF-8 encoded headers. When decoding frame headers, the
41 * following transformations MUST be applied:
42 *
43 * \n (octet 92 and 110) translates to newline (octet 10)
44 * \c (octet 92 and 99) translates to : (octet 58)
45 * \\ (octet 92 and 92) translates to \ (octet 92)
46 */
f05a636 Elias Karakoulakis valgrind memcheck: first round of bug-killing
authored
47 string& encode_header_token(string& str) {
48 boost::algorithm::replace_all(str, "\n", "\\n");
49 boost::algorithm::replace_all(str, ":", "\\c");
50 boost::algorithm::replace_all(str, "\\", "\\\\");
51 return(str);
45fd176 Elias Karakoulakis - added static+dynamic lib target in Makefile
authored
52 };
53
f05a636 Elias Karakoulakis valgrind memcheck: first round of bug-killing
authored
54 string& decode_header_token(string& str) {
55 boost::algorithm::replace_all(str, "\\n", "\n");
56 boost::algorithm::replace_all(str, "\\c", ":");
57 boost::algorithm::replace_all(str, "\\\\", "\\");
58 return(str);
45fd176 Elias Karakoulakis - added static+dynamic lib target in Makefile
authored
59 };
60
7b0a3cd Elias Karakoulakis - valgrind has revealed subtle thread sync bugs. Fixed.
authored
61 boost::asio::streambuf& Frame::encode(boost::asio::streambuf& _request)
45fd176 Elias Karakoulakis - added static+dynamic lib target in Makefile
authored
62 // -------------------------------------
63 {
64 // prepare an output stream
7b0a3cd Elias Karakoulakis - valgrind has revealed subtle thread sync bugs. Fixed.
authored
65 ostream os(&_request);
45fd176 Elias Karakoulakis - added static+dynamic lib target in Makefile
authored
66 // step 1. write the command
67 if (m_command.length() > 0) {
68 os << m_command << "\n";
69 } else {
70 throw("stomp_write: command not set!!");
71 }
72 // step 2. Write the headers (key-value pairs)
73 if( m_headers.size() > 0 ) {
74 for ( hdrmap::iterator it = m_headers.begin() ; it != m_headers.end(); it++ ) {
f05a636 Elias Karakoulakis valgrind memcheck: first round of bug-killing
authored
75 string key = (*it).first;
76 string val = (*it).second;
77 os << encode_header_token(key)
45fd176 Elias Karakoulakis - added static+dynamic lib target in Makefile
authored
78 << ":"
f05a636 Elias Karakoulakis valgrind memcheck: first round of bug-killing
authored
79 << encode_header_token(val)
45fd176 Elias Karakoulakis - added static+dynamic lib target in Makefile
authored
80 << "\n";
81 }
82 }
83 // special header: content-length
965308b Elias Karakoulakis yay! binary bodies in frames!
authored
84 if( m_body.v.size() > 0 ) {
85 os << "content-length:" << m_body.v.size() << "\n";
45fd176 Elias Karakoulakis - added static+dynamic lib target in Makefile
authored
86 }
87 // write newline signifying end of headers
88 os << "\n";
89 // step 3. Write the body
965308b Elias Karakoulakis yay! binary bodies in frames!
authored
90 if( m_body.v.size() > 0 ) {
7b0a3cd Elias Karakoulakis - valgrind has revealed subtle thread sync bugs. Fixed.
authored
91 _request.sputn(m_body.v.data(), m_body.v.size());
92 //_request.commit(m_body.v.size());
45fd176 Elias Karakoulakis - added static+dynamic lib target in Makefile
authored
93 }
94 // write terminating NULL char
7b0a3cd Elias Karakoulakis - valgrind has revealed subtle thread sync bugs. Fixed.
authored
95 _request.sputc('\0');
96 //_request.commit(1);
97 return(_request);
98 };
99
100 // my own version of getline for an asio streambuf
101 inline void mygetline (boost::asio::streambuf& sb, string& _str, char delim = '\n') {
102 const char* line = boost::asio::buffer_cast<const char*>(sb.data());
103 char _c;
104 _str.clear();
105 for( size_t i = 0;
106 ((i < sb.size()) && ((_c = line[i]) != delim));
107 i++
108 ) _str += _c;
a1714ef Elias Karakoulakis - made write calls synchronous
authored
109 //debug_print( boost::format("mygetline: sb.size==%1%") % sb.size() );
110 //hexdump(_str.c_str(), _str.size());
7b0a3cd Elias Karakoulakis - valgrind has revealed subtle thread sync bugs. Fixed.
authored
111 }
112
113 // construct STOMP frame (command & header) from a streambuf
114 // --------------------------------------------------
115 Frame::Frame(boost::asio::streambuf& stomp_response, const stomp_server_command_map_t& cmd_map)
116 // --------------------------------------------------
117 {
118 string _str;
119
120 try {
121 // STEP 1: find the next STOMP command line in stomp_response.
122 // Chomp unknown lines till the buffer is empty, in which case an exception is raised
a1714ef Elias Karakoulakis - made write calls synchronous
authored
123 //debug_print("Frame parser phase 1");
7b0a3cd Elias Karakoulakis - valgrind has revealed subtle thread sync bugs. Fixed.
authored
124 while (stomp_response.size() > 0) {
125 mygetline(stomp_response, _str);
126 //hexdump(_str.c_str(), _str.length());
127 stomp_response.consume(_str.size() + 1); // plus one for the newline
128 if (_str.size() > 0) {
129 if (cmd_map.find(_str) != cmd_map.end()) {
a1714ef Elias Karakoulakis - made write calls synchronous
authored
130 //debug_print(boost::format("phase 1: COMMAND==%1%, sb.size==%2%") % _str % stomp_response.size());
7b0a3cd Elias Karakoulakis - valgrind has revealed subtle thread sync bugs. Fixed.
authored
131 m_command = _str;
132 break;
133 }
134 } else {
135 throw(NoMoreFrames());
136 }
137 }
138
139 // STEP 2: parse all headers
a1714ef Elias Karakoulakis - made write calls synchronous
authored
140 //debug_print("Frame parser phase 2");
7b0a3cd Elias Karakoulakis - valgrind has revealed subtle thread sync bugs. Fixed.
authored
141 vector< string > header_parts;
142 while (stomp_response.size() > 0) {
143 mygetline(stomp_response, _str);
144 stomp_response.consume(_str.size()+1);
145 boost::algorithm::split(header_parts, _str, is_any_of(":"));
146 if (header_parts.size() > 1) {
147 string key = decode_header_token(header_parts[0]);
148 string val = decode_header_token(header_parts[1]);
a1714ef Elias Karakoulakis - made write calls synchronous
authored
149 //debug_print(boost::format("phase 2: HEADER[%1%]==%2%") % key % val);
7b0a3cd Elias Karakoulakis - valgrind has revealed subtle thread sync bugs. Fixed.
authored
150 m_headers[key] = val;
151 //
152 } else {
153 // no valid header line detected, on to the body scanner
154 break;
155 }
156 }
157 //
158 } catch(NoMoreFrames& e) {
a1714ef Elias Karakoulakis - made write calls synchronous
authored
159 //debug_print("-- Frame parser ended (no more frames)");
7b0a3cd Elias Karakoulakis - valgrind has revealed subtle thread sync bugs. Fixed.
authored
160 throw(e);
161 }
45fd176 Elias Karakoulakis - added static+dynamic lib target in Makefile
authored
162 };
163
7b0a3cd Elias Karakoulakis - valgrind has revealed subtle thread sync bugs. Fixed.
authored
164 // STEP 3: parse the body
165 size_t Frame::parse_body(boost::asio::streambuf& _response)
166 {
167 std::size_t _content_length = 0, bytecount = 0;
168 string _str;
a1714ef Elias Karakoulakis - made write calls synchronous
authored
169 //debug_print("Frame parser phase 3");
7b0a3cd Elias Karakoulakis - valgrind has revealed subtle thread sync bugs. Fixed.
authored
170
171 // special case: content-length
172 if (m_headers.find("content-length") != m_headers.end()) {
173 string val = m_headers["content-length"];
174 _content_length = lexical_cast<int>(val);
a1714ef Elias Karakoulakis - made write calls synchronous
authored
175 //debug_print(boost::format("phase 3: body content-length==%1%") % _content_length);
7b0a3cd Elias Karakoulakis - valgrind has revealed subtle thread sync bugs. Fixed.
authored
176 }
177 if (_content_length > 0) {
178 bytecount += _content_length;
179 // read back the body byte by byte
180 const char* rawdata = boost::asio::buffer_cast<const char*>(_response.data());
181 for (size_t i = 0; i < _content_length; i++ ) {
182 m_body << rawdata[i];
183 }
184 } else {
185 // read all bytes until the first NULL
186 mygetline(_response, _str, '\0');
187 bytecount += _str.size();
188 m_body << _str;
189 }
190 bytecount += 1; // for the final frame-terminating NULL
a1714ef Elias Karakoulakis - made write calls synchronous
authored
191 //debug_print(boost::format("phase 3: consumed %1% bytes, BODY(%2% bytes)==%3%") % bytecount % _str.size() % _str);
7b0a3cd Elias Karakoulakis - valgrind has revealed subtle thread sync bugs. Fixed.
authored
192 _response.consume(bytecount);
193 return(bytecount);
194 }
195
45fd176 Elias Karakoulakis - added static+dynamic lib target in Makefile
authored
196 }
Something went wrong with that request. Please try again.