Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit ddcc3a53 authored by Jesse Wilson's avatar Jesse Wilson Committed by Android (Google) Code Review
Browse files

Merge "Interpret '+' as a space char in the URL query params."

parents ff35661b 0f28af20
Loading
Loading
Loading
Loading
+8 −105
Original line number Diff line number Diff line
@@ -19,12 +19,10 @@ package android.net;
import android.os.Parcel;
import android.os.Parcelable;
import android.util.Log;

import java.io.File;
import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.io.ByteArrayOutputStream;
import java.net.URLEncoder;
import java.nio.charset.Charsets;
import java.util.AbstractList;
import java.util.ArrayList;
import java.util.Collections;
@@ -32,6 +30,7 @@ import java.util.LinkedHashSet;
import java.util.List;
import java.util.RandomAccess;
import java.util.Set;
import libcore.net.UriCodec;

/**
 * Immutable URI reference. A URI reference includes a URI and a fragment, the
@@ -1681,7 +1680,8 @@ public abstract class Uri implements Parcelable, Comparable<Uri> {
                if (separator == end) {
                    return "";
                } else {
                  return decode(query.substring(separator + 1, end));
                    String encodedValue = query.substring(separator + 1, end);
                    return UriCodec.decode(encodedValue, true, Charsets.UTF_8, false);
                }
            }

@@ -1877,9 +1877,6 @@ public abstract class Uri implements Parcelable, Comparable<Uri> {
                || (allow != null && allow.indexOf(c) != NOT_FOUND);
    }

    /** Unicode replacement character: \\uFFFD. */
    private static final byte[] REPLACEMENT = { (byte) 0xFF, (byte) 0xFD };

    /**
     * Decodes '%'-escaped octets in the given string using the UTF-8 scheme.
     * Replaces invalid octets with the unicode replacement character
@@ -1890,104 +1887,10 @@ public abstract class Uri implements Parcelable, Comparable<Uri> {
     *  s is null
     */
    public static String decode(String s) {
        /*
        Compared to java.net.URLEncoderDecoder.decode(), this method decodes a
        chunk at a time instead of one character at a time, and it doesn't
        throw exceptions. It also only allocates memory when necessary--if
        there's nothing to decode, this method won't do much.
        */

        if (s == null) {
            return null;
        }

        // Lazily-initialized buffers.
        StringBuilder decoded = null;
        ByteArrayOutputStream out = null;

        int oldLength = s.length();

        // This loop alternates between copying over normal characters and
        // escaping in chunks. This results in fewer method calls and
        // allocations than decoding one character at a time.
        int current = 0;
        while (current < oldLength) {
            // Start in "copying" mode where we copy over normal characters.

            // Find the next escape sequence.
            int nextEscape = s.indexOf('%', current);

            if (nextEscape == NOT_FOUND) {
                if (decoded == null) {
                    // We didn't actually decode anything.
                    return s;
                } else {
                    // Append the remainder and return the decoded string.
                    decoded.append(s, current, oldLength);
                    return decoded.toString();
                }
            }

            // Prepare buffers.
            if (decoded == null) {
                // Looks like we're going to need the buffers...
                // We know the new string will be shorter. Using the old length
                // may overshoot a bit, but it will save us from resizing the
                // buffer.
                decoded = new StringBuilder(oldLength);
                out = new ByteArrayOutputStream(4);
            } else {
                // Clear decoding buffer.
                out.reset();
            }

            // Append characters leading up to the escape.
            if (nextEscape > current) {
                decoded.append(s, current, nextEscape);

                current = nextEscape;
            } else {
                // assert current == nextEscape
            }

            // Switch to "decoding" mode where we decode a string of escape
            // sequences.

            // Decode and append escape sequences. Escape sequences look like
            // "%ab" where % is literal and a and b are hex digits.
            try {
                do {
                    if (current + 2 >= oldLength) {
                        // Truncated escape sequence.
                        out.write(REPLACEMENT);
                    } else {
                        int a = Character.digit(s.charAt(current + 1), 16);
                        int b = Character.digit(s.charAt(current + 2), 16);

                        if (a == -1 || b == -1) {
                            // Non hex digits.
                            out.write(REPLACEMENT);
                        } else {
                            // Combine the hex digits into one byte and write.
                            out.write((a << 4) + b);
                        }
                    }

                    // Move passed the escape sequence.
                    current += 3;
                } while (current < oldLength && s.charAt(current) == '%');

                // Decode UTF-8 bytes into a string and append it.
                decoded.append(out.toString(DEFAULT_ENCODING));
            } catch (UnsupportedEncodingException e) {
                throw new AssertionError(e);
            } catch (IOException e) {
                throw new AssertionError(e);
            }
        }

        // If we don't have a buffer, we didn't have to decode anything.
        return decoded == null ? s : decoded.toString();
        return UriCodec.decode(s, false, Charsets.UTF_8, false);
    }

    /**
+9 −5
Original line number Diff line number Diff line
@@ -16,17 +16,15 @@

package android.net;

import android.net.Uri;
import android.content.ContentUris;
import android.os.Parcel;
import android.test.suitebuilder.annotation.SmallTest;
import junit.framework.TestCase;

import java.io.File;
import java.util.Arrays;
import java.util.Iterator;
import java.util.List;
import java.util.Set;
import junit.framework.TestCase;

public class UriTest extends TestCase {

@@ -748,4 +746,10 @@ public class UriTest extends TestCase {
        assertEquals(Arrays.asList("a", "", ""),
                Uri.parse("http://foo/path?abc=a&abc=&abc=").getQueryParameters("abc"));
    }

    // http://code.google.com/p/android/issues/detail?id=21064
    public void testPlusCharacterInQuery() {
        assertEquals("d e", Uri.parse("http://a/b?c=d%20e").getQueryParameter("c"));
        assertEquals("d e", Uri.parse("http://a/b?c=d+e").getQueryParameter("c"));
    }
}