|
1 | 1 | // Copyright (c) 2015-2016 The Bitcoin Core developers
|
| 2 | +// Copyright (c) 2017 The Zcash developers |
2 | 3 | // Distributed under the MIT software license, see the accompanying
|
3 | 4 | // file COPYING or http://www.opensource.org/licenses/mit-license.php.
|
4 | 5 |
|
@@ -291,17 +292,61 @@ static std::map<std::string,std::string> ParseTorReplyMapping(const std::string
|
291 | 292 | ++ptr; // skip opening '"'
|
292 | 293 | bool escape_next = false;
|
293 | 294 | while (ptr < s.size() && (escape_next || s[ptr] != '"')) {
|
294 |
| - escape_next = (s[ptr] == '\\'); |
| 295 | + // Repeated backslashes must be interpreted as pairs |
| 296 | + escape_next = (s[ptr] == '\\' && !escape_next); |
295 | 297 | value.push_back(s[ptr]);
|
296 | 298 | ++ptr;
|
297 | 299 | }
|
298 | 300 | if (ptr == s.size()) // unexpected end of line
|
299 | 301 | return std::map<std::string,std::string>();
|
300 | 302 | ++ptr; // skip closing '"'
|
301 |
| - /* TODO: unescape value - according to the spec this depends on the |
302 |
| - * context, some strings use C-LogPrintf style escape codes, some |
303 |
| - * don't. So may be better handled at the call site. |
| 303 | + /** |
| 304 | + * Unescape value. Per https://spec.torproject.org/control-spec section 2.1.1: |
| 305 | + * |
| 306 | + * For future-proofing, controller implementors MAY use the following |
| 307 | + * rules to be compatible with buggy Tor implementations and with |
| 308 | + * future ones that implement the spec as intended: |
| 309 | + * |
| 310 | + * Read \n \t \r and \0 ... \377 as C escapes. |
| 311 | + * Treat a backslash followed by any other character as that character. |
304 | 312 | */
|
| 313 | + std::string escaped_value; |
| 314 | + for (size_t i = 0; i < value.size(); ++i) { |
| 315 | + if (value[i] == '\\') { |
| 316 | + // This will always be valid, because if the QuotedString |
| 317 | + // ended in an odd number of backslashes, then the parser |
| 318 | + // would already have returned above, due to a missing |
| 319 | + // terminating double-quote. |
| 320 | + ++i; |
| 321 | + if (value[i] == 'n') { |
| 322 | + escaped_value.push_back('\n'); |
| 323 | + } else if (value[i] == 't') { |
| 324 | + escaped_value.push_back('\t'); |
| 325 | + } else if (value[i] == 'r') { |
| 326 | + escaped_value.push_back('\r'); |
| 327 | + } else if ('0' <= value[i] && value[i] <= '7') { |
| 328 | + size_t j; |
| 329 | + // Octal escape sequences have a limit of three octal digits, |
| 330 | + // but terminate at the first character that is not a valid |
| 331 | + // octal digit if encountered sooner. |
| 332 | + for (j = 1; j < 3 && (i+j) < value.size() && '0' <= value[i+j] && value[i+j] <= '7'; ++j) {} |
| 333 | + // Tor restricts first digit to 0-3 for three-digit octals. |
| 334 | + // A leading digit of 4-7 would therefore be interpreted as |
| 335 | + // a two-digit octal. |
| 336 | + if (j == 3 && value[i] > '3') { |
| 337 | + j--; |
| 338 | + } |
| 339 | + escaped_value.push_back(strtol(value.substr(i, j).c_str(), NULL, 8)); |
| 340 | + // Account for automatic incrementing at loop end |
| 341 | + i += j - 1; |
| 342 | + } else { |
| 343 | + escaped_value.push_back(value[i]); |
| 344 | + } |
| 345 | + } else { |
| 346 | + escaped_value.push_back(value[i]); |
| 347 | + } |
| 348 | + } |
| 349 | + value = escaped_value; |
305 | 350 | } else { // Unquoted value. Note that values can contain '=' at will, just no spaces
|
306 | 351 | while (ptr < s.size() && s[ptr] != ' ') {
|
307 | 352 | value.push_back(s[ptr]);
|
|
0 commit comments