From b0fa5435a2b9db9eae3ec2b51bd72b4193ce0b7a Mon Sep 17 00:00:00 2001 From: Andreas Schildbach Date: Mon, 21 Apr 2014 18:51:07 +0200 Subject: [PATCH] Fix parsing of empty labels and messages, and parsing of labels and messages with an unescaped equals sign in their value. --- .../com/google/bitcoin/uri/BitcoinURI.java | 21 ++++--- .../google/bitcoin/uri/BitcoinURITest.java | 55 ++++--------------- 2 files changed, 23 insertions(+), 53 deletions(-) diff --git a/core/src/main/java/com/google/bitcoin/uri/BitcoinURI.java b/core/src/main/java/com/google/bitcoin/uri/BitcoinURI.java index 0e8219ae2..899c3846a 100644 --- a/core/src/main/java/com/google/bitcoin/uri/BitcoinURI.java +++ b/core/src/main/java/com/google/bitcoin/uri/BitcoinURI.java @@ -1,5 +1,5 @@ /* - * Copyright 2012 the original author or authors. + * Copyright 2012, 2014 the original author or authors. * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -32,6 +32,7 @@ import java.net.URI; import java.net.URISyntaxException; import java.net.URLDecoder; import java.util.LinkedHashMap; +import java.util.Locale; import java.util.Map; import static com.google.common.base.Preconditions.checkNotNull; @@ -192,14 +193,15 @@ public class BitcoinURI { private void parseParameters(@Nullable NetworkParameters params, String addressToken, String[] nameValuePairTokens) throws BitcoinURIParseException { // Attempt to decode the rest of the tokens into a parameter map. for (String nameValuePairToken : nameValuePairTokens) { - String[] tokens = nameValuePairToken.split("="); - if (tokens.length != 2 || "".equals(tokens[0])) { - throw new BitcoinURIParseException("Malformed Bitcoin URI - cannot parse name value pair '" + + final int sepIndex = nameValuePairToken.indexOf('='); + if (sepIndex == -1) + throw new BitcoinURIParseException("Malformed Bitcoin URI - no separator in '" + nameValuePairToken + "'"); - } - - String nameToken = tokens[0].toLowerCase(); - String valueToken = tokens[1]; + if (sepIndex == 0) + throw new BitcoinURIParseException("Malformed Bitcoin URI - empty name '" + + nameValuePairToken + "'"); + final String nameToken = nameValuePairToken.substring(0, sepIndex).toLowerCase(Locale.ENGLISH); + final String valueToken = nameValuePairToken.substring(sepIndex + 1); // Parse the amount. if (FIELD_AMOUNT.equals(nameToken)) { @@ -219,7 +221,8 @@ public class BitcoinURI { } else { // Known fields and unknown parameters that are optional. try { - putWithValidation(nameToken, URLDecoder.decode(valueToken, "UTF-8")); + if (valueToken.length() > 0) + putWithValidation(nameToken, URLDecoder.decode(valueToken, "UTF-8")); } catch (UnsupportedEncodingException e) { // Unreachable. throw new RuntimeException(e); diff --git a/core/src/test/java/com/google/bitcoin/uri/BitcoinURITest.java b/core/src/test/java/com/google/bitcoin/uri/BitcoinURITest.java index ba63e191b..150a4181a 100644 --- a/core/src/test/java/com/google/bitcoin/uri/BitcoinURITest.java +++ b/core/src/test/java/com/google/bitcoin/uri/BitcoinURITest.java @@ -1,5 +1,5 @@ /* - * Copyright 2012 the original author or authors. + * Copyright 2012, 2014 the original author or authors. * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -271,38 +271,16 @@ public class BitcoinURITest { } } - /** - * Handles a badly formatted label field - * - * @throws BitcoinURIParseException - * If something goes wrong - */ @Test - public void testBad_Label() throws BitcoinURIParseException { - try { - testObject = new BitcoinURI(MainNetParams.get(), BitcoinURI.BITCOIN_SCHEME + ":" + MAINNET_GOOD_ADDRESS - + "?label="); - fail("Expecting BitcoinURIParseException"); - } catch (BitcoinURIParseException e) { - assertTrue(e.getMessage().contains("label")); - } + public void testEmpty_Label() throws BitcoinURIParseException { + assertNull(new BitcoinURI(MainNetParams.get(), BitcoinURI.BITCOIN_SCHEME + ":" + MAINNET_GOOD_ADDRESS + + "?label=").getLabel()); } - /** - * Handles a badly formatted message field - * - * @throws BitcoinURIParseException - * If something goes wrong - */ @Test - public void testBad_Message() throws BitcoinURIParseException { - try { - testObject = new BitcoinURI(MainNetParams.get(), BitcoinURI.BITCOIN_SCHEME + ":" + MAINNET_GOOD_ADDRESS - + "?message="); - fail("Expecting BitcoinURIParseException"); - } catch (BitcoinURIParseException e) { - assertTrue(e.getMessage().contains("message")); - } + public void testEmpty_Message() throws BitcoinURIParseException { + assertNull(new BitcoinURI(MainNetParams.get(), BitcoinURI.BITCOIN_SCHEME + ":" + MAINNET_GOOD_ADDRESS + + "?message=").getMessage()); } /** @@ -322,21 +300,10 @@ public class BitcoinURITest { } } - /** - * Handles case when there are too many equals - * - * @throws BitcoinURIParseException - * If something goes wrong - */ @Test - public void testBad_TooManyEquals() throws BitcoinURIParseException { - try { - testObject = new BitcoinURI(MainNetParams.get(), BitcoinURI.BITCOIN_SCHEME + ":" + MAINNET_GOOD_ADDRESS - + "?label=aardvark=zebra"); - fail("Expecting BitcoinURIParseException"); - } catch (BitcoinURIParseException e) { - assertTrue(e.getMessage().contains("cannot parse name value pair")); - } + public void testGood_ManyEquals() throws BitcoinURIParseException { + assertEquals("aardvark=zebra", new BitcoinURI(MainNetParams.get(), BitcoinURI.BITCOIN_SCHEME + ":" + + MAINNET_GOOD_ADDRESS + "?label=aardvark=zebra").getLabel()); } /** @@ -377,7 +344,7 @@ public class BitcoinURITest { + "?aardvark"); fail("Expecting BitcoinURIParseException"); } catch (BitcoinURIParseException e) { - assertTrue(e.getMessage().contains("cannot parse name value pair")); + assertTrue(e.getMessage().contains("no separator")); } // Unknown and required field