summaryrefslogtreecommitdiffstats
path: root/mobile/android/thirdparty/ch/boye/httpclientandroidlib/client/utils
diff options
context:
space:
mode:
Diffstat (limited to 'mobile/android/thirdparty/ch/boye/httpclientandroidlib/client/utils')
-rw-r--r--mobile/android/thirdparty/ch/boye/httpclientandroidlib/client/utils/CloneUtils.java86
-rw-r--r--mobile/android/thirdparty/ch/boye/httpclientandroidlib/client/utils/DateUtils.java250
-rw-r--r--mobile/android/thirdparty/ch/boye/httpclientandroidlib/client/utils/HttpClientUtils.java149
-rw-r--r--mobile/android/thirdparty/ch/boye/httpclientandroidlib/client/utils/Idn.java42
-rw-r--r--mobile/android/thirdparty/ch/boye/httpclientandroidlib/client/utils/JdkIdn.java71
-rw-r--r--mobile/android/thirdparty/ch/boye/httpclientandroidlib/client/utils/Punycode.java54
-rw-r--r--mobile/android/thirdparty/ch/boye/httpclientandroidlib/client/utils/Rfc3492Idn.java141
-rw-r--r--mobile/android/thirdparty/ch/boye/httpclientandroidlib/client/utils/URIBuilder.java490
-rw-r--r--mobile/android/thirdparty/ch/boye/httpclientandroidlib/client/utils/URIUtils.java428
-rw-r--r--mobile/android/thirdparty/ch/boye/httpclientandroidlib/client/utils/URLEncodedUtils.java628
-rw-r--r--mobile/android/thirdparty/ch/boye/httpclientandroidlib/client/utils/package-info.java31
11 files changed, 2370 insertions, 0 deletions
diff --git a/mobile/android/thirdparty/ch/boye/httpclientandroidlib/client/utils/CloneUtils.java b/mobile/android/thirdparty/ch/boye/httpclientandroidlib/client/utils/CloneUtils.java
new file mode 100644
index 000000000..67f70ee07
--- /dev/null
+++ b/mobile/android/thirdparty/ch/boye/httpclientandroidlib/client/utils/CloneUtils.java
@@ -0,0 +1,86 @@
+/*
+ * ====================================================================
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ * ====================================================================
+ *
+ * This software consists of voluntary contributions made by many
+ * individuals on behalf of the Apache Software Foundation. For more
+ * information on the Apache Software Foundation, please see
+ * <http://www.apache.org/>.
+ *
+ */
+package ch.boye.httpclientandroidlib.client.utils;
+
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Method;
+
+import ch.boye.httpclientandroidlib.annotation.Immutable;
+
+/**
+ * A collection of utilities to workaround limitations of Java clone framework.
+ *
+ * @since 4.0
+ */
+@Immutable
+public class CloneUtils {
+
+ /**
+ * @since 4.3
+ */
+ public static <T> T cloneObject(final T obj) throws CloneNotSupportedException {
+ if (obj == null) {
+ return null;
+ }
+ if (obj instanceof Cloneable) {
+ final Class<?> clazz = obj.getClass ();
+ final Method m;
+ try {
+ m = clazz.getMethod("clone", (Class[]) null);
+ } catch (final NoSuchMethodException ex) {
+ throw new NoSuchMethodError(ex.getMessage());
+ }
+ try {
+ @SuppressWarnings("unchecked") // OK because clone() preserves the class
+ final T result = (T) m.invoke(obj, (Object []) null);
+ return result;
+ } catch (final InvocationTargetException ex) {
+ final Throwable cause = ex.getCause();
+ if (cause instanceof CloneNotSupportedException) {
+ throw ((CloneNotSupportedException) cause);
+ } else {
+ throw new Error("Unexpected exception", cause);
+ }
+ } catch (final IllegalAccessException ex) {
+ throw new IllegalAccessError(ex.getMessage());
+ }
+ } else {
+ throw new CloneNotSupportedException();
+ }
+ }
+
+ public static Object clone(final Object obj) throws CloneNotSupportedException {
+ return cloneObject(obj);
+ }
+
+ /**
+ * This class should not be instantiated.
+ */
+ private CloneUtils() {
+ }
+
+}
diff --git a/mobile/android/thirdparty/ch/boye/httpclientandroidlib/client/utils/DateUtils.java b/mobile/android/thirdparty/ch/boye/httpclientandroidlib/client/utils/DateUtils.java
new file mode 100644
index 000000000..e337923d3
--- /dev/null
+++ b/mobile/android/thirdparty/ch/boye/httpclientandroidlib/client/utils/DateUtils.java
@@ -0,0 +1,250 @@
+/*
+ * ====================================================================
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ * ====================================================================
+ *
+ * This software consists of voluntary contributions made by many
+ * individuals on behalf of the Apache Software Foundation. For more
+ * information on the Apache Software Foundation, please see
+ * <http://www.apache.org/>.
+ *
+ */
+
+package ch.boye.httpclientandroidlib.client.utils;
+
+import java.lang.ref.SoftReference;
+import java.text.ParsePosition;
+import java.text.SimpleDateFormat;
+import java.util.Calendar;
+import java.util.Date;
+import java.util.HashMap;
+import java.util.Locale;
+import java.util.Map;
+import java.util.TimeZone;
+
+import ch.boye.httpclientandroidlib.annotation.Immutable;
+import ch.boye.httpclientandroidlib.util.Args;
+
+/**
+ * A utility class for parsing and formatting HTTP dates as used in cookies and
+ * other headers. This class handles dates as defined by RFC 2616 section
+ * 3.3.1 as well as some other common non-standard formats.
+ *
+ * @since 4.3
+ */
+@Immutable
+public final class DateUtils {
+
+ /**
+ * Date format pattern used to parse HTTP date headers in RFC 1123 format.
+ */
+ public static final String PATTERN_RFC1123 = "EEE, dd MMM yyyy HH:mm:ss zzz";
+
+ /**
+ * Date format pattern used to parse HTTP date headers in RFC 1036 format.
+ */
+ public static final String PATTERN_RFC1036 = "EEE, dd-MMM-yy HH:mm:ss zzz";
+
+ /**
+ * Date format pattern used to parse HTTP date headers in ANSI C
+ * <code>asctime()</code> format.
+ */
+ public static final String PATTERN_ASCTIME = "EEE MMM d HH:mm:ss yyyy";
+
+ private static final String[] DEFAULT_PATTERNS = new String[] {
+ PATTERN_RFC1123,
+ PATTERN_RFC1036,
+ PATTERN_ASCTIME
+ };
+
+ private static final Date DEFAULT_TWO_DIGIT_YEAR_START;
+
+ public static final TimeZone GMT = TimeZone.getTimeZone("GMT");
+
+ static {
+ final Calendar calendar = Calendar.getInstance();
+ calendar.setTimeZone(GMT);
+ calendar.set(2000, Calendar.JANUARY, 1, 0, 0, 0);
+ calendar.set(Calendar.MILLISECOND, 0);
+ DEFAULT_TWO_DIGIT_YEAR_START = calendar.getTime();
+ }
+
+ /**
+ * Parses a date value. The formats used for parsing the date value are retrieved from
+ * the default http params.
+ *
+ * @param dateValue the date value to parse
+ *
+ * @return the parsed date or null if input could not be parsed
+ */
+ public static Date parseDate(final String dateValue) {
+ return parseDate(dateValue, null, null);
+ }
+
+ /**
+ * Parses the date value using the given date formats.
+ *
+ * @param dateValue the date value to parse
+ * @param dateFormats the date formats to use
+ *
+ * @return the parsed date or null if input could not be parsed
+ */
+ public static Date parseDate(final String dateValue, final String[] dateFormats) {
+ return parseDate(dateValue, dateFormats, null);
+ }
+
+ /**
+ * Parses the date value using the given date formats.
+ *
+ * @param dateValue the date value to parse
+ * @param dateFormats the date formats to use
+ * @param startDate During parsing, two digit years will be placed in the range
+ * <code>startDate</code> to <code>startDate + 100 years</code>. This value may
+ * be <code>null</code>. When <code>null</code> is given as a parameter, year
+ * <code>2000</code> will be used.
+ *
+ * @return the parsed date or null if input could not be parsed
+ */
+ public static Date parseDate(
+ final String dateValue,
+ final String[] dateFormats,
+ final Date startDate) {
+ Args.notNull(dateValue, "Date value");
+ final String[] localDateFormats = dateFormats != null ? dateFormats : DEFAULT_PATTERNS;
+ final Date localStartDate = startDate != null ? startDate : DEFAULT_TWO_DIGIT_YEAR_START;
+ String v = dateValue;
+ // trim single quotes around date if present
+ // see issue #5279
+ if (v.length() > 1 && v.startsWith("'") && v.endsWith("'")) {
+ v = v.substring (1, v.length() - 1);
+ }
+
+ for (final String dateFormat : localDateFormats) {
+ final SimpleDateFormat dateParser = DateFormatHolder.formatFor(dateFormat);
+ dateParser.set2DigitYearStart(localStartDate);
+ final ParsePosition pos = new ParsePosition(0);
+ final Date result = dateParser.parse(v, pos);
+ if (pos.getIndex() != 0) {
+ return result;
+ }
+ }
+ return null;
+ }
+
+ /**
+ * Formats the given date according to the RFC 1123 pattern.
+ *
+ * @param date The date to format.
+ * @return An RFC 1123 formatted date string.
+ *
+ * @see #PATTERN_RFC1123
+ */
+ public static String formatDate(final Date date) {
+ return formatDate(date, PATTERN_RFC1123);
+ }
+
+ /**
+ * Formats the given date according to the specified pattern. The pattern
+ * must conform to that used by the {@link SimpleDateFormat simple date
+ * format} class.
+ *
+ * @param date The date to format.
+ * @param pattern The pattern to use for formatting the date.
+ * @return A formatted date string.
+ *
+ * @throws IllegalArgumentException If the given date pattern is invalid.
+ *
+ * @see SimpleDateFormat
+ */
+ public static String formatDate(final Date date, final String pattern) {
+ Args.notNull(date, "Date");
+ Args.notNull(pattern, "Pattern");
+ final SimpleDateFormat formatter = DateFormatHolder.formatFor(pattern);
+ return formatter.format(date);
+ }
+
+ /**
+ * Clears thread-local variable containing {@link java.text.DateFormat} cache.
+ *
+ * @since 4.3
+ */
+ public static void clearThreadLocal() {
+ DateFormatHolder.clearThreadLocal();
+ }
+
+ /** This class should not be instantiated. */
+ private DateUtils() {
+ }
+
+ /**
+ * A factory for {@link SimpleDateFormat}s. The instances are stored in a
+ * threadlocal way because SimpleDateFormat is not threadsafe as noted in
+ * {@link SimpleDateFormat its javadoc}.
+ *
+ */
+ final static class DateFormatHolder {
+
+ private static final ThreadLocal<SoftReference<Map<String, SimpleDateFormat>>>
+ THREADLOCAL_FORMATS = new ThreadLocal<SoftReference<Map<String, SimpleDateFormat>>>() {
+
+ @Override
+ protected SoftReference<Map<String, SimpleDateFormat>> initialValue() {
+ return new SoftReference<Map<String, SimpleDateFormat>>(
+ new HashMap<String, SimpleDateFormat>());
+ }
+
+ };
+
+ /**
+ * creates a {@link SimpleDateFormat} for the requested format string.
+ *
+ * @param pattern
+ * a non-<code>null</code> format String according to
+ * {@link SimpleDateFormat}. The format is not checked against
+ * <code>null</code> since all paths go through
+ * {@link DateUtils}.
+ * @return the requested format. This simple dateformat should not be used
+ * to {@link SimpleDateFormat#applyPattern(String) apply} to a
+ * different pattern.
+ */
+ public static SimpleDateFormat formatFor(final String pattern) {
+ final SoftReference<Map<String, SimpleDateFormat>> ref = THREADLOCAL_FORMATS.get();
+ Map<String, SimpleDateFormat> formats = ref.get();
+ if (formats == null) {
+ formats = new HashMap<String, SimpleDateFormat>();
+ THREADLOCAL_FORMATS.set(
+ new SoftReference<Map<String, SimpleDateFormat>>(formats));
+ }
+
+ SimpleDateFormat format = formats.get(pattern);
+ if (format == null) {
+ format = new SimpleDateFormat(pattern, Locale.US);
+ format.setTimeZone(TimeZone.getTimeZone("GMT"));
+ formats.put(pattern, format);
+ }
+
+ return format;
+ }
+
+ public static void clearThreadLocal() {
+ THREADLOCAL_FORMATS.remove();
+ }
+
+ }
+
+}
diff --git a/mobile/android/thirdparty/ch/boye/httpclientandroidlib/client/utils/HttpClientUtils.java b/mobile/android/thirdparty/ch/boye/httpclientandroidlib/client/utils/HttpClientUtils.java
new file mode 100644
index 000000000..3c7769c2a
--- /dev/null
+++ b/mobile/android/thirdparty/ch/boye/httpclientandroidlib/client/utils/HttpClientUtils.java
@@ -0,0 +1,149 @@
+/*
+ * ====================================================================
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ * ====================================================================
+ *
+ * This software consists of voluntary contributions made by many
+ * individuals on behalf of the Apache Software Foundation. For more
+ * information on the Apache Software Foundation, please see
+ * <http://www.apache.org/>.
+ *
+ */
+package ch.boye.httpclientandroidlib.client.utils;
+
+import java.io.Closeable;
+import java.io.IOException;
+
+import ch.boye.httpclientandroidlib.HttpEntity;
+import ch.boye.httpclientandroidlib.HttpResponse;
+import ch.boye.httpclientandroidlib.client.HttpClient;
+import ch.boye.httpclientandroidlib.client.methods.CloseableHttpResponse;
+import ch.boye.httpclientandroidlib.util.EntityUtils;
+
+/**
+ * Convenience methods for closing response and client objects.
+ *
+ * @since 4.2
+ */
+public class HttpClientUtils {
+
+ private HttpClientUtils() {
+ }
+
+ /**
+ * Unconditionally close a response.
+ * <p>
+ * Example Code:
+ *
+ * <pre>
+ * HttpResponse httpResponse = null;
+ * try {
+ * httpResponse = httpClient.execute(httpGet);
+ * } catch (Exception e) {
+ * // error handling
+ * } finally {
+ * HttpClientUtils.closeQuietly(httpResponse);
+ * }
+ * </pre>
+ *
+ * @param response
+ * the HttpResponse to release resources, may be null or already
+ * closed.
+ *
+ * @since 4.2
+ */
+ public static void closeQuietly(final HttpResponse response) {
+ if (response != null) {
+ final HttpEntity entity = response.getEntity();
+ if (entity != null) {
+ try {
+ EntityUtils.consume(entity);
+ } catch (final IOException ex) {
+ }
+ }
+ }
+ }
+
+ /**
+ * Unconditionally close a response.
+ * <p>
+ * Example Code:
+ *
+ * <pre>
+ * HttpResponse httpResponse = null;
+ * try {
+ * httpResponse = httpClient.execute(httpGet);
+ * } catch (Exception e) {
+ * // error handling
+ * } finally {
+ * HttpClientUtils.closeQuietly(httpResponse);
+ * }
+ * </pre>
+ *
+ * @param response
+ * the HttpResponse to release resources, may be null or already
+ * closed.
+ *
+ * @since 4.3
+ */
+ public static void closeQuietly(final CloseableHttpResponse response) {
+ if (response != null) {
+ try {
+ try {
+ EntityUtils.consume(response.getEntity());
+ } finally {
+ response.close();
+ }
+ } catch (final IOException ignore) {
+ }
+ }
+ }
+
+ /**
+ * Unconditionally close a httpClient. Shuts down the underlying connection
+ * manager and releases the resources.
+ * <p>
+ * Example Code:
+ *
+ * <pre>
+ * HttpClient httpClient = HttpClients.createDefault();
+ * try {
+ * httpClient.execute(request);
+ * } catch (Exception e) {
+ * // error handling
+ * } finally {
+ * HttpClientUtils.closeQuietly(httpClient);
+ * }
+ * </pre>
+ *
+ * @param httpClient
+ * the HttpClient to close, may be null or already closed.
+ * @since 4.2
+ */
+ public static void closeQuietly(final HttpClient httpClient) {
+ if (httpClient != null) {
+ if (httpClient instanceof Closeable) {
+ try {
+ ((Closeable) httpClient).close();
+ } catch (final IOException ignore) {
+ }
+ }
+ }
+ }
+
+}
diff --git a/mobile/android/thirdparty/ch/boye/httpclientandroidlib/client/utils/Idn.java b/mobile/android/thirdparty/ch/boye/httpclientandroidlib/client/utils/Idn.java
new file mode 100644
index 000000000..a2b5bd036
--- /dev/null
+++ b/mobile/android/thirdparty/ch/boye/httpclientandroidlib/client/utils/Idn.java
@@ -0,0 +1,42 @@
+/*
+ * ====================================================================
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ * ====================================================================
+ *
+ * This software consists of voluntary contributions made by many
+ * individuals on behalf of the Apache Software Foundation. For more
+ * information on the Apache Software Foundation, please see
+ * <http://www.apache.org/>.
+ *
+ */
+package ch.boye.httpclientandroidlib.client.utils;
+
+/**
+ * Abstraction of international domain name (IDN) conversion.
+ *
+ * @since 4.0
+ */
+public interface Idn {
+ /**
+ * Converts a name from its punycode representation to Unicode.
+ * The name may be a single hostname or a dot-separated qualified domain name.
+ * @param punycode the Punycode representation
+ * @return the Unicode domain name
+ */
+ String toUnicode(String punycode);
+}
diff --git a/mobile/android/thirdparty/ch/boye/httpclientandroidlib/client/utils/JdkIdn.java b/mobile/android/thirdparty/ch/boye/httpclientandroidlib/client/utils/JdkIdn.java
new file mode 100644
index 000000000..53d46fe23
--- /dev/null
+++ b/mobile/android/thirdparty/ch/boye/httpclientandroidlib/client/utils/JdkIdn.java
@@ -0,0 +1,71 @@
+/*
+ * ====================================================================
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ * ====================================================================
+ *
+ * This software consists of voluntary contributions made by many
+ * individuals on behalf of the Apache Software Foundation. For more
+ * information on the Apache Software Foundation, please see
+ * <http://www.apache.org/>.
+ *
+ */
+package ch.boye.httpclientandroidlib.client.utils;
+
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Method;
+
+import ch.boye.httpclientandroidlib.annotation.Immutable;
+
+/**
+ * Uses the java.net.IDN class through reflection.
+ *
+ * @since 4.0
+ */
+@Immutable
+public class JdkIdn implements Idn {
+ private final Method toUnicode;
+
+ /**
+ *
+ * @throws ClassNotFoundException if java.net.IDN is not available
+ */
+ public JdkIdn() throws ClassNotFoundException {
+ final Class<?> clazz = Class.forName("java.net.IDN");
+ try {
+ toUnicode = clazz.getMethod("toUnicode", String.class);
+ } catch (final SecurityException e) {
+ // doesn't happen
+ throw new IllegalStateException(e.getMessage(), e);
+ } catch (final NoSuchMethodException e) {
+ // doesn't happen
+ throw new IllegalStateException(e.getMessage(), e);
+ }
+ }
+
+ public String toUnicode(final String punycode) {
+ try {
+ return (String) toUnicode.invoke(null, punycode);
+ } catch (final IllegalAccessException e) {
+ throw new IllegalStateException(e.getMessage(), e);
+ } catch (final InvocationTargetException e) {
+ final Throwable t = e.getCause();
+ throw new RuntimeException(t.getMessage(), t);
+ }
+ }
+
+}
diff --git a/mobile/android/thirdparty/ch/boye/httpclientandroidlib/client/utils/Punycode.java b/mobile/android/thirdparty/ch/boye/httpclientandroidlib/client/utils/Punycode.java
new file mode 100644
index 000000000..fa4872c41
--- /dev/null
+++ b/mobile/android/thirdparty/ch/boye/httpclientandroidlib/client/utils/Punycode.java
@@ -0,0 +1,54 @@
+/*
+ * ====================================================================
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ * ====================================================================
+ *
+ * This software consists of voluntary contributions made by many
+ * individuals on behalf of the Apache Software Foundation. For more
+ * information on the Apache Software Foundation, please see
+ * <http://www.apache.org/>.
+ *
+ */
+package ch.boye.httpclientandroidlib.client.utils;
+
+import ch.boye.httpclientandroidlib.annotation.Immutable;
+
+/**
+ * Facade that provides conversion between Unicode and Punycode domain names.
+ * It will use an appropriate implementation.
+ *
+ * @since 4.0
+ */
+@Immutable
+public class Punycode {
+ private static final Idn impl;
+ static {
+ Idn _impl;
+ try {
+ _impl = new JdkIdn();
+ } catch (final Exception e) {
+ _impl = new Rfc3492Idn();
+ }
+ impl = _impl;
+ }
+
+ public static String toUnicode(final String punycode) {
+ return impl.toUnicode(punycode);
+ }
+
+}
diff --git a/mobile/android/thirdparty/ch/boye/httpclientandroidlib/client/utils/Rfc3492Idn.java b/mobile/android/thirdparty/ch/boye/httpclientandroidlib/client/utils/Rfc3492Idn.java
new file mode 100644
index 000000000..ccf980050
--- /dev/null
+++ b/mobile/android/thirdparty/ch/boye/httpclientandroidlib/client/utils/Rfc3492Idn.java
@@ -0,0 +1,141 @@
+/*
+ * ====================================================================
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ * ====================================================================
+ *
+ * This software consists of voluntary contributions made by many
+ * individuals on behalf of the Apache Software Foundation. For more
+ * information on the Apache Software Foundation, please see
+ * <http://www.apache.org/>.
+ *
+ */
+package ch.boye.httpclientandroidlib.client.utils;
+
+import java.util.StringTokenizer;
+
+import ch.boye.httpclientandroidlib.annotation.Immutable;
+
+/**
+ * Implementation from pseudo code in RFC 3492.
+ *
+ * @since 4.0
+ */
+@Immutable
+public class Rfc3492Idn implements Idn {
+ private static final int base = 36;
+ private static final int tmin = 1;
+ private static final int tmax = 26;
+ private static final int skew = 38;
+ private static final int damp = 700;
+ private static final int initial_bias = 72;
+ private static final int initial_n = 128;
+ private static final char delimiter = '-';
+ private static final String ACE_PREFIX = "xn--";
+
+ private int adapt(final int delta, final int numpoints, final boolean firsttime) {
+ int d = delta;
+ if (firsttime) {
+ d = d / damp;
+ } else {
+ d = d / 2;
+ }
+ d = d + (d / numpoints);
+ int k = 0;
+ while (d > ((base - tmin) * tmax) / 2) {
+ d = d / (base - tmin);
+ k = k + base;
+ }
+ return k + (((base - tmin + 1) * d) / (d + skew));
+ }
+
+ private int digit(final char c) {
+ if ((c >= 'A') && (c <= 'Z')) {
+ return (c - 'A');
+ }
+ if ((c >= 'a') && (c <= 'z')) {
+ return (c - 'a');
+ }
+ if ((c >= '0') && (c <= '9')) {
+ return (c - '0') + 26;
+ }
+ throw new IllegalArgumentException("illegal digit: "+ c);
+ }
+
+ public String toUnicode(final String punycode) {
+ final StringBuilder unicode = new StringBuilder(punycode.length());
+ final StringTokenizer tok = new StringTokenizer(punycode, ".");
+ while (tok.hasMoreTokens()) {
+ String t = tok.nextToken();
+ if (unicode.length() > 0) {
+ unicode.append('.');
+ }
+ if (t.startsWith(ACE_PREFIX)) {
+ t = decode(t.substring(4));
+ }
+ unicode.append(t);
+ }
+ return unicode.toString();
+ }
+
+ protected String decode(final String s) {
+ String input = s;
+ int n = initial_n;
+ int i = 0;
+ int bias = initial_bias;
+ final StringBuilder output = new StringBuilder(input.length());
+ final int lastdelim = input.lastIndexOf(delimiter);
+ if (lastdelim != -1) {
+ output.append(input.subSequence(0, lastdelim));
+ input = input.substring(lastdelim + 1);
+ }
+
+ while (input.length() > 0) {
+ final int oldi = i;
+ int w = 1;
+ for (int k = base;; k += base) {
+ if (input.length() == 0) {
+ break;
+ }
+ final char c = input.charAt(0);
+ input = input.substring(1);
+ final int digit = digit(c);
+ i = i + digit * w; // FIXME fail on overflow
+ final int t;
+ if (k <= bias + tmin) {
+ t = tmin;
+ } else if (k >= bias + tmax) {
+ t = tmax;
+ } else {
+ t = k - bias;
+ }
+ if (digit < t) {
+ break;
+ }
+ w = w * (base - t); // FIXME fail on overflow
+ }
+ bias = adapt(i - oldi, output.length() + 1, (oldi == 0));
+ n = n + i / (output.length() + 1); // FIXME fail on overflow
+ i = i % (output.length() + 1);
+ // {if n is a basic code point then fail}
+ output.insert(i, (char) n);
+ i++;
+ }
+ return output.toString();
+ }
+
+}
diff --git a/mobile/android/thirdparty/ch/boye/httpclientandroidlib/client/utils/URIBuilder.java b/mobile/android/thirdparty/ch/boye/httpclientandroidlib/client/utils/URIBuilder.java
new file mode 100644
index 000000000..e41958f7f
--- /dev/null
+++ b/mobile/android/thirdparty/ch/boye/httpclientandroidlib/client/utils/URIBuilder.java
@@ -0,0 +1,490 @@
+/*
+ * ====================================================================
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ * ====================================================================
+ *
+ * This software consists of voluntary contributions made by many
+ * individuals on behalf of the Apache Software Foundation. For more
+ * information on the Apache Software Foundation, please see
+ * <http://www.apache.org/>.
+ *
+ */
+package ch.boye.httpclientandroidlib.client.utils;
+
+import java.net.URI;
+import java.net.URISyntaxException;
+import java.nio.charset.Charset;
+import java.util.ArrayList;
+import java.util.Iterator;
+import java.util.List;
+
+import ch.boye.httpclientandroidlib.Consts;
+import ch.boye.httpclientandroidlib.NameValuePair;
+import ch.boye.httpclientandroidlib.annotation.NotThreadSafe;
+import ch.boye.httpclientandroidlib.conn.util.InetAddressUtils;
+import ch.boye.httpclientandroidlib.message.BasicNameValuePair;
+
+/**
+ * Builder for {@link URI} instances.
+ *
+ * @since 4.2
+ */
+@NotThreadSafe
+public class URIBuilder {
+
+ private String scheme;
+ private String encodedSchemeSpecificPart;
+ private String encodedAuthority;
+ private String userInfo;
+ private String encodedUserInfo;
+ private String host;
+ private int port;
+ private String path;
+ private String encodedPath;
+ private String encodedQuery;
+ private List<NameValuePair> queryParams;
+ private String query;
+ private String fragment;
+ private String encodedFragment;
+
+ /**
+ * Constructs an empty instance.
+ */
+ public URIBuilder() {
+ super();
+ this.port = -1;
+ }
+
+ /**
+ * Construct an instance from the string which must be a valid URI.
+ *
+ * @param string a valid URI in string form
+ * @throws URISyntaxException if the input is not a valid URI
+ */
+ public URIBuilder(final String string) throws URISyntaxException {
+ super();
+ digestURI(new URI(string));
+ }
+
+ /**
+ * Construct an instance from the provided URI.
+ * @param uri
+ */
+ public URIBuilder(final URI uri) {
+ super();
+ digestURI(uri);
+ }
+
+ private List <NameValuePair> parseQuery(final String query, final Charset charset) {
+ if (query != null && query.length() > 0) {
+ return URLEncodedUtils.parse(query, charset);
+ }
+ return null;
+ }
+
+ /**
+ * Builds a {@link URI} instance.
+ */
+ public URI build() throws URISyntaxException {
+ return new URI(buildString());
+ }
+
+ private String buildString() {
+ final StringBuilder sb = new StringBuilder();
+ if (this.scheme != null) {
+ sb.append(this.scheme).append(':');
+ }
+ if (this.encodedSchemeSpecificPart != null) {
+ sb.append(this.encodedSchemeSpecificPart);
+ } else {
+ if (this.encodedAuthority != null) {
+ sb.append("//").append(this.encodedAuthority);
+ } else if (this.host != null) {
+ sb.append("//");
+ if (this.encodedUserInfo != null) {
+ sb.append(this.encodedUserInfo).append("@");
+ } else if (this.userInfo != null) {
+ sb.append(encodeUserInfo(this.userInfo)).append("@");
+ }
+ if (InetAddressUtils.isIPv6Address(this.host)) {
+ sb.append("[").append(this.host).append("]");
+ } else {
+ sb.append(this.host);
+ }
+ if (this.port >= 0) {
+ sb.append(":").append(this.port);
+ }
+ }
+ if (this.encodedPath != null) {
+ sb.append(normalizePath(this.encodedPath));
+ } else if (this.path != null) {
+ sb.append(encodePath(normalizePath(this.path)));
+ }
+ if (this.encodedQuery != null) {
+ sb.append("?").append(this.encodedQuery);
+ } else if (this.queryParams != null) {
+ sb.append("?").append(encodeUrlForm(this.queryParams));
+ } else if (this.query != null) {
+ sb.append("?").append(encodeUric(this.query));
+ }
+ }
+ if (this.encodedFragment != null) {
+ sb.append("#").append(this.encodedFragment);
+ } else if (this.fragment != null) {
+ sb.append("#").append(encodeUric(this.fragment));
+ }
+ return sb.toString();
+ }
+
+ private void digestURI(final URI uri) {
+ this.scheme = uri.getScheme();
+ this.encodedSchemeSpecificPart = uri.getRawSchemeSpecificPart();
+ this.encodedAuthority = uri.getRawAuthority();
+ this.host = uri.getHost();
+ this.port = uri.getPort();
+ this.encodedUserInfo = uri.getRawUserInfo();
+ this.userInfo = uri.getUserInfo();
+ this.encodedPath = uri.getRawPath();
+ this.path = uri.getPath();
+ this.encodedQuery = uri.getRawQuery();
+ this.queryParams = parseQuery(uri.getRawQuery(), Consts.UTF_8);
+ this.encodedFragment = uri.getRawFragment();
+ this.fragment = uri.getFragment();
+ }
+
+ private String encodeUserInfo(final String userInfo) {
+ return URLEncodedUtils.encUserInfo(userInfo, Consts.UTF_8);
+ }
+
+ private String encodePath(final String path) {
+ return URLEncodedUtils.encPath(path, Consts.UTF_8);
+ }
+
+ private String encodeUrlForm(final List<NameValuePair> params) {
+ return URLEncodedUtils.format(params, Consts.UTF_8);
+ }
+
+ private String encodeUric(final String fragment) {
+ return URLEncodedUtils.encUric(fragment, Consts.UTF_8);
+ }
+
+ /**
+ * Sets URI scheme.
+ */
+ public URIBuilder setScheme(final String scheme) {
+ this.scheme = scheme;
+ return this;
+ }
+
+ /**
+ * Sets URI user info. The value is expected to be unescaped and may contain non ASCII
+ * characters.
+ */
+ public URIBuilder setUserInfo(final String userInfo) {
+ this.userInfo = userInfo;
+ this.encodedSchemeSpecificPart = null;
+ this.encodedAuthority = null;
+ this.encodedUserInfo = null;
+ return this;
+ }
+
+ /**
+ * Sets URI user info as a combination of username and password. These values are expected to
+ * be unescaped and may contain non ASCII characters.
+ */
+ public URIBuilder setUserInfo(final String username, final String password) {
+ return setUserInfo(username + ':' + password);
+ }
+
+ /**
+ * Sets URI host.
+ */
+ public URIBuilder setHost(final String host) {
+ this.host = host;
+ this.encodedSchemeSpecificPart = null;
+ this.encodedAuthority = null;
+ return this;
+ }
+
+ /**
+ * Sets URI port.
+ */
+ public URIBuilder setPort(final int port) {
+ this.port = port < 0 ? -1 : port;
+ this.encodedSchemeSpecificPart = null;
+ this.encodedAuthority = null;
+ return this;
+ }
+
+ /**
+ * Sets URI path. The value is expected to be unescaped and may contain non ASCII characters.
+ */
+ public URIBuilder setPath(final String path) {
+ this.path = path;
+ this.encodedSchemeSpecificPart = null;
+ this.encodedPath = null;
+ return this;
+ }
+
+ /**
+ * Removes URI query.
+ */
+ public URIBuilder removeQuery() {
+ this.queryParams = null;
+ this.query = null;
+ this.encodedQuery = null;
+ this.encodedSchemeSpecificPart = null;
+ return this;
+ }
+
+ /**
+ * Sets URI query.
+ * <p>
+ * The value is expected to be encoded form data.
+ *
+ * @deprecated (4.3) use {@link #setParameters(List)} or {@link #setParameters(NameValuePair...)}
+ *
+ * @see URLEncodedUtils#parse
+ */
+ @Deprecated
+ public URIBuilder setQuery(final String query) {
+ this.queryParams = parseQuery(query, Consts.UTF_8);
+ this.query = null;
+ this.encodedQuery = null;
+ this.encodedSchemeSpecificPart = null;
+ return this;
+ }
+
+ /**
+ * Sets URI query parameters. The parameter name / values are expected to be unescaped
+ * and may contain non ASCII characters.
+ * <p/>
+ * Please note query parameters and custom query component are mutually exclusive. This method
+ * will remove custom query if present.
+ *
+ * @since 4.3
+ */
+ public URIBuilder setParameters(final List <NameValuePair> nvps) {
+ if (this.queryParams == null) {
+ this.queryParams = new ArrayList<NameValuePair>();
+ } else {
+ this.queryParams.clear();
+ }
+ this.queryParams.addAll(nvps);
+ this.encodedQuery = null;
+ this.encodedSchemeSpecificPart = null;
+ this.query = null;
+ return this;
+ }
+
+ /**
+ * Adds URI query parameters. The parameter name / values are expected to be unescaped
+ * and may contain non ASCII characters.
+ * <p/>
+ * Please note query parameters and custom query component are mutually exclusive. This method
+ * will remove custom query if present.
+ *
+ * @since 4.3
+ */
+ public URIBuilder addParameters(final List <NameValuePair> nvps) {
+ if (this.queryParams == null) {
+ this.queryParams = new ArrayList<NameValuePair>();
+ }
+ this.queryParams.addAll(nvps);
+ this.encodedQuery = null;
+ this.encodedSchemeSpecificPart = null;
+ this.query = null;
+ return this;
+ }
+
+ /**
+ * Sets URI query parameters. The parameter name / values are expected to be unescaped
+ * and may contain non ASCII characters.
+ * <p/>
+ * Please note query parameters and custom query component are mutually exclusive. This method
+ * will remove custom query if present.
+ *
+ * @since 4.3
+ */
+ public URIBuilder setParameters(final NameValuePair... nvps) {
+ if (this.queryParams == null) {
+ this.queryParams = new ArrayList<NameValuePair>();
+ } else {
+ this.queryParams.clear();
+ }
+ for (final NameValuePair nvp: nvps) {
+ this.queryParams.add(nvp);
+ }
+ this.encodedQuery = null;
+ this.encodedSchemeSpecificPart = null;
+ this.query = null;
+ return this;
+ }
+
+ /**
+ * Adds parameter to URI query. The parameter name and value are expected to be unescaped
+ * and may contain non ASCII characters.
+ * <p/>
+ * Please note query parameters and custom query component are mutually exclusive. This method
+ * will remove custom query if present.
+ */
+ public URIBuilder addParameter(final String param, final String value) {
+ if (this.queryParams == null) {
+ this.queryParams = new ArrayList<NameValuePair>();
+ }
+ this.queryParams.add(new BasicNameValuePair(param, value));
+ this.encodedQuery = null;
+ this.encodedSchemeSpecificPart = null;
+ this.query = null;
+ return this;
+ }
+
+ /**
+ * Sets parameter of URI query overriding existing value if set. The parameter name and value
+ * are expected to be unescaped and may contain non ASCII characters.
+ * <p/>
+ * Please note query parameters and custom query component are mutually exclusive. This method
+ * will remove custom query if present.
+ */
+ public URIBuilder setParameter(final String param, final String value) {
+ if (this.queryParams == null) {
+ this.queryParams = new ArrayList<NameValuePair>();
+ }
+ if (!this.queryParams.isEmpty()) {
+ for (final Iterator<NameValuePair> it = this.queryParams.iterator(); it.hasNext(); ) {
+ final NameValuePair nvp = it.next();
+ if (nvp.getName().equals(param)) {
+ it.remove();
+ }
+ }
+ }
+ this.queryParams.add(new BasicNameValuePair(param, value));
+ this.encodedQuery = null;
+ this.encodedSchemeSpecificPart = null;
+ this.query = null;
+ return this;
+ }
+
+ /**
+ * Clears URI query parameters.
+ *
+ * @since 4.3
+ */
+ public URIBuilder clearParameters() {
+ this.queryParams = null;
+ this.encodedQuery = null;
+ this.encodedSchemeSpecificPart = null;
+ return this;
+ }
+
+ /**
+ * Sets custom URI query. The value is expected to be unescaped and may contain non ASCII
+ * characters.
+ * <p/>
+ * Please note query parameters and custom query component are mutually exclusive. This method
+ * will remove query parameters if present.
+ *
+ * @since 4.3
+ */
+ public URIBuilder setCustomQuery(final String query) {
+ this.query = query;
+ this.encodedQuery = null;
+ this.encodedSchemeSpecificPart = null;
+ this.queryParams = null;
+ return this;
+ }
+
+ /**
+ * Sets URI fragment. The value is expected to be unescaped and may contain non ASCII
+ * characters.
+ */
+ public URIBuilder setFragment(final String fragment) {
+ this.fragment = fragment;
+ this.encodedFragment = null;
+ return this;
+ }
+
+ /**
+ * @since 4.3
+ */
+ public boolean isAbsolute() {
+ return this.scheme != null;
+ }
+
+ /**
+ * @since 4.3
+ */
+ public boolean isOpaque() {
+ return this.path == null;
+ }
+
+ public String getScheme() {
+ return this.scheme;
+ }
+
+ public String getUserInfo() {
+ return this.userInfo;
+ }
+
+ public String getHost() {
+ return this.host;
+ }
+
+ public int getPort() {
+ return this.port;
+ }
+
+ public String getPath() {
+ return this.path;
+ }
+
+ public List<NameValuePair> getQueryParams() {
+ if (this.queryParams != null) {
+ return new ArrayList<NameValuePair>(this.queryParams);
+ } else {
+ return new ArrayList<NameValuePair>();
+ }
+ }
+
+ public String getFragment() {
+ return this.fragment;
+ }
+
+ @Override
+ public String toString() {
+ return buildString();
+ }
+
+ private static String normalizePath(final String path) {
+ String s = path;
+ if (s == null) {
+ return null;
+ }
+ int n = 0;
+ for (; n < s.length(); n++) {
+ if (s.charAt(n) != '/') {
+ break;
+ }
+ }
+ if (n > 1) {
+ s = s.substring(n - 1);
+ }
+ return s;
+ }
+
+}
diff --git a/mobile/android/thirdparty/ch/boye/httpclientandroidlib/client/utils/URIUtils.java b/mobile/android/thirdparty/ch/boye/httpclientandroidlib/client/utils/URIUtils.java
new file mode 100644
index 000000000..73619c90a
--- /dev/null
+++ b/mobile/android/thirdparty/ch/boye/httpclientandroidlib/client/utils/URIUtils.java
@@ -0,0 +1,428 @@
+/*
+ * ====================================================================
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ * ====================================================================
+ *
+ * This software consists of voluntary contributions made by many
+ * individuals on behalf of the Apache Software Foundation. For more
+ * information on the Apache Software Foundation, please see
+ * <http://www.apache.org/>.
+ *
+ */
+package ch.boye.httpclientandroidlib.client.utils;
+
+import java.net.URI;
+import java.net.URISyntaxException;
+import java.util.List;
+import java.util.Locale;
+import java.util.Stack;
+
+import ch.boye.httpclientandroidlib.HttpHost;
+import ch.boye.httpclientandroidlib.annotation.Immutable;
+import ch.boye.httpclientandroidlib.util.Args;
+import ch.boye.httpclientandroidlib.util.TextUtils;
+
+/**
+ * A collection of utilities for {@link URI URIs}, to workaround
+ * bugs within the class or for ease-of-use features.
+ *
+ * @since 4.0
+ */
+@Immutable
+public class URIUtils {
+
+ /**
+ * Constructs a {@link URI} using all the parameters. This should be
+ * used instead of
+ * {@link URI#URI(String, String, String, int, String, String, String)}
+ * or any of the other URI multi-argument URI constructors.
+ *
+ * @param scheme
+ * Scheme name
+ * @param host
+ * Host name
+ * @param port
+ * Port number
+ * @param path
+ * Path
+ * @param query
+ * Query
+ * @param fragment
+ * Fragment
+ *
+ * @throws URISyntaxException
+ * If both a scheme and a path are given but the path is
+ * relative, if the URI string constructed from the given
+ * components violates RFC&nbsp;2396, or if the authority
+ * component of the string is present but cannot be parsed
+ * as a server-based authority
+ *
+ * @deprecated (4.2) use {@link URIBuilder}.
+ */
+ @Deprecated
+ public static URI createURI(
+ final String scheme,
+ final String host,
+ final int port,
+ final String path,
+ final String query,
+ final String fragment) throws URISyntaxException {
+ final StringBuilder buffer = new StringBuilder();
+ if (host != null) {
+ if (scheme != null) {
+ buffer.append(scheme);
+ buffer.append("://");
+ }
+ buffer.append(host);
+ if (port > 0) {
+ buffer.append(':');
+ buffer.append(port);
+ }
+ }
+ if (path == null || !path.startsWith("/")) {
+ buffer.append('/');
+ }
+ if (path != null) {
+ buffer.append(path);
+ }
+ if (query != null) {
+ buffer.append('?');
+ buffer.append(query);
+ }
+ if (fragment != null) {
+ buffer.append('#');
+ buffer.append(fragment);
+ }
+ return new URI(buffer.toString());
+ }
+
+ /**
+ * A convenience method for creating a new {@link URI} whose scheme, host
+ * and port are taken from the target host, but whose path, query and
+ * fragment are taken from the existing URI. The fragment is only used if
+ * dropFragment is false. The path is set to "/" if not explicitly specified.
+ *
+ * @param uri
+ * Contains the path, query and fragment to use.
+ * @param target
+ * Contains the scheme, host and port to use.
+ * @param dropFragment
+ * True if the fragment should not be copied.
+ *
+ * @throws URISyntaxException
+ * If the resulting URI is invalid.
+ */
+ public static URI rewriteURI(
+ final URI uri,
+ final HttpHost target,
+ final boolean dropFragment) throws URISyntaxException {
+ Args.notNull(uri, "URI");
+ if (uri.isOpaque()) {
+ return uri;
+ }
+ final URIBuilder uribuilder = new URIBuilder(uri);
+ if (target != null) {
+ uribuilder.setScheme(target.getSchemeName());
+ uribuilder.setHost(target.getHostName());
+ uribuilder.setPort(target.getPort());
+ } else {
+ uribuilder.setScheme(null);
+ uribuilder.setHost(null);
+ uribuilder.setPort(-1);
+ }
+ if (dropFragment) {
+ uribuilder.setFragment(null);
+ }
+ if (TextUtils.isEmpty(uribuilder.getPath())) {
+ uribuilder.setPath("/");
+ }
+ return uribuilder.build();
+ }
+
+ /**
+ * A convenience method for
+ * {@link URIUtils#rewriteURI(URI, HttpHost, boolean)} that always keeps the
+ * fragment.
+ */
+ public static URI rewriteURI(
+ final URI uri,
+ final HttpHost target) throws URISyntaxException {
+ return rewriteURI(uri, target, false);
+ }
+
+ /**
+ * A convenience method that creates a new {@link URI} whose scheme, host, port, path,
+ * query are taken from the existing URI, dropping any fragment or user-information.
+ * The path is set to "/" if not explicitly specified. The existing URI is returned
+ * unmodified if it has no fragment or user-information and has a path.
+ *
+ * @param uri
+ * original URI.
+ * @throws URISyntaxException
+ * If the resulting URI is invalid.
+ */
+ public static URI rewriteURI(final URI uri) throws URISyntaxException {
+ Args.notNull(uri, "URI");
+ if (uri.isOpaque()) {
+ return uri;
+ }
+ final URIBuilder uribuilder = new URIBuilder(uri);
+ if (uribuilder.getUserInfo() != null) {
+ uribuilder.setUserInfo(null);
+ }
+ if (TextUtils.isEmpty(uribuilder.getPath())) {
+ uribuilder.setPath("/");
+ }
+ if (uribuilder.getHost() != null) {
+ uribuilder.setHost(uribuilder.getHost().toLowerCase(Locale.ENGLISH));
+ }
+ uribuilder.setFragment(null);
+ return uribuilder.build();
+ }
+
+ /**
+ * Resolves a URI reference against a base URI. Work-around for bug in
+ * java.net.URI (<http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=4708535>)
+ *
+ * @param baseURI the base URI
+ * @param reference the URI reference
+ * @return the resulting URI
+ */
+ public static URI resolve(final URI baseURI, final String reference) {
+ return URIUtils.resolve(baseURI, URI.create(reference));
+ }
+
+ /**
+ * Resolves a URI reference against a base URI. Work-around for bugs in
+ * java.net.URI (e.g. <http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=4708535>)
+ *
+ * @param baseURI the base URI
+ * @param reference the URI reference
+ * @return the resulting URI
+ */
+ public static URI resolve(final URI baseURI, final URI reference){
+ Args.notNull(baseURI, "Base URI");
+ Args.notNull(reference, "Reference URI");
+ URI ref = reference;
+ final String s = ref.toString();
+ if (s.startsWith("?")) {
+ return resolveReferenceStartingWithQueryString(baseURI, ref);
+ }
+ final boolean emptyReference = s.length() == 0;
+ if (emptyReference) {
+ ref = URI.create("#");
+ }
+ URI resolved = baseURI.resolve(ref);
+ if (emptyReference) {
+ final String resolvedString = resolved.toString();
+ resolved = URI.create(resolvedString.substring(0,
+ resolvedString.indexOf('#')));
+ }
+ return normalizeSyntax(resolved);
+ }
+
+ /**
+ * Resolves a reference starting with a query string.
+ *
+ * @param baseURI the base URI
+ * @param reference the URI reference starting with a query string
+ * @return the resulting URI
+ */
+ private static URI resolveReferenceStartingWithQueryString(
+ final URI baseURI, final URI reference) {
+ String baseUri = baseURI.toString();
+ baseUri = baseUri.indexOf('?') > -1 ?
+ baseUri.substring(0, baseUri.indexOf('?')) : baseUri;
+ return URI.create(baseUri + reference.toString());
+ }
+
+ /**
+ * Removes dot segments according to RFC 3986, section 5.2.4 and
+ * Syntax-Based Normalization according to RFC 3986, section 6.2.2.
+ *
+ * @param uri the original URI
+ * @return the URI without dot segments
+ */
+ private static URI normalizeSyntax(final URI uri) {
+ if (uri.isOpaque() || uri.getAuthority() == null) {
+ // opaque and file: URIs
+ return uri;
+ }
+ Args.check(uri.isAbsolute(), "Base URI must be absolute");
+ final String path = uri.getPath() == null ? "" : uri.getPath();
+ final String[] inputSegments = path.split("/");
+ final Stack<String> outputSegments = new Stack<String>();
+ for (final String inputSegment : inputSegments) {
+ if ((inputSegment.length() == 0)
+ || (".".equals(inputSegment))) {
+ // Do nothing
+ } else if ("..".equals(inputSegment)) {
+ if (!outputSegments.isEmpty()) {
+ outputSegments.pop();
+ }
+ } else {
+ outputSegments.push(inputSegment);
+ }
+ }
+ final StringBuilder outputBuffer = new StringBuilder();
+ for (final String outputSegment : outputSegments) {
+ outputBuffer.append('/').append(outputSegment);
+ }
+ if (path.lastIndexOf('/') == path.length() - 1) {
+ // path.endsWith("/") || path.equals("")
+ outputBuffer.append('/');
+ }
+ try {
+ final String scheme = uri.getScheme().toLowerCase(Locale.ENGLISH);
+ final String auth = uri.getAuthority().toLowerCase(Locale.ENGLISH);
+ final URI ref = new URI(scheme, auth, outputBuffer.toString(),
+ null, null);
+ if (uri.getQuery() == null && uri.getFragment() == null) {
+ return ref;
+ }
+ final StringBuilder normalized = new StringBuilder(
+ ref.toASCIIString());
+ if (uri.getQuery() != null) {
+ // query string passed through unchanged
+ normalized.append('?').append(uri.getRawQuery());
+ }
+ if (uri.getFragment() != null) {
+ // fragment passed through unchanged
+ normalized.append('#').append(uri.getRawFragment());
+ }
+ return URI.create(normalized.toString());
+ } catch (final URISyntaxException e) {
+ throw new IllegalArgumentException(e);
+ }
+ }
+
+ /**
+ * Extracts target host from the given {@link URI}.
+ *
+ * @param uri
+ * @return the target host if the URI is absolute or <code>null</null> if the URI is
+ * relative or does not contain a valid host name.
+ *
+ * @since 4.1
+ */
+ public static HttpHost extractHost(final URI uri) {
+ if (uri == null) {
+ return null;
+ }
+ HttpHost target = null;
+ if (uri.isAbsolute()) {
+ int port = uri.getPort(); // may be overridden later
+ String host = uri.getHost();
+ if (host == null) { // normal parse failed; let's do it ourselves
+ // authority does not seem to care about the valid character-set for host names
+ host = uri.getAuthority();
+ if (host != null) {
+ // Strip off any leading user credentials
+ final int at = host.indexOf('@');
+ if (at >= 0) {
+ if (host.length() > at+1 ) {
+ host = host.substring(at+1);
+ } else {
+ host = null; // @ on its own
+ }
+ }
+ // Extract the port suffix, if present
+ if (host != null) {
+ final int colon = host.indexOf(':');
+ if (colon >= 0) {
+ final int pos = colon + 1;
+ int len = 0;
+ for (int i = pos; i < host.length(); i++) {
+ if (Character.isDigit(host.charAt(i))) {
+ len++;
+ } else {
+ break;
+ }
+ }
+ if (len > 0) {
+ try {
+ port = Integer.parseInt(host.substring(pos, pos + len));
+ } catch (final NumberFormatException ex) {
+ }
+ }
+ host = host.substring(0, colon);
+ }
+ }
+ }
+ }
+ final String scheme = uri.getScheme();
+ if (!TextUtils.isBlank(host)) {
+ target = new HttpHost(host, port, scheme);
+ }
+ }
+ return target;
+ }
+
+ /**
+ * Derives the interpreted (absolute) URI that was used to generate the last
+ * request. This is done by extracting the request-uri and target origin for
+ * the last request and scanning all the redirect locations for the last
+ * fragment identifier, then combining the result into a {@link URI}.
+ *
+ * @param originalURI
+ * original request before any redirects
+ * @param target
+ * if the last URI is relative, it is resolved against this target,
+ * or <code>null</code> if not available.
+ * @param redirects
+ * collection of redirect locations since the original request
+ * or <code>null</code> if not available.
+ * @return interpreted (absolute) URI
+ */
+ public static URI resolve(
+ final URI originalURI,
+ final HttpHost target,
+ final List<URI> redirects) throws URISyntaxException {
+ Args.notNull(originalURI, "Request URI");
+ final URIBuilder uribuilder;
+ if (redirects == null || redirects.isEmpty()) {
+ uribuilder = new URIBuilder(originalURI);
+ } else {
+ uribuilder = new URIBuilder(redirects.get(redirects.size() - 1));
+ String frag = uribuilder.getFragment();
+ // read interpreted fragment identifier from redirect locations
+ for (int i = redirects.size() - 1; frag == null && i >= 0; i--) {
+ frag = redirects.get(i).getFragment();
+ }
+ uribuilder.setFragment(frag);
+ }
+ // read interpreted fragment identifier from original request
+ if (uribuilder.getFragment() == null) {
+ uribuilder.setFragment(originalURI.getFragment());
+ }
+ // last target origin
+ if (target != null && !uribuilder.isAbsolute()) {
+ uribuilder.setScheme(target.getSchemeName());
+ uribuilder.setHost(target.getHostName());
+ uribuilder.setPort(target.getPort());
+ }
+ return uribuilder.build();
+ }
+
+ /**
+ * This class should not be instantiated.
+ */
+ private URIUtils() {
+ }
+
+}
diff --git a/mobile/android/thirdparty/ch/boye/httpclientandroidlib/client/utils/URLEncodedUtils.java b/mobile/android/thirdparty/ch/boye/httpclientandroidlib/client/utils/URLEncodedUtils.java
new file mode 100644
index 000000000..97465401f
--- /dev/null
+++ b/mobile/android/thirdparty/ch/boye/httpclientandroidlib/client/utils/URLEncodedUtils.java
@@ -0,0 +1,628 @@
+/*
+ * ====================================================================
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ * ====================================================================
+ *
+ * This software consists of voluntary contributions made by many
+ * individuals on behalf of the Apache Software Foundation. For more
+ * information on the Apache Software Foundation, please see
+ * <http://www.apache.org/>.
+ *
+ */
+
+package ch.boye.httpclientandroidlib.client.utils;
+
+import java.io.IOException;
+import java.net.URI;
+import java.nio.ByteBuffer;
+import java.nio.CharBuffer;
+import java.nio.charset.Charset;
+import java.util.ArrayList;
+import java.util.BitSet;
+import java.util.Collections;
+import java.util.List;
+import java.util.Scanner;
+
+import ch.boye.httpclientandroidlib.Consts;
+import ch.boye.httpclientandroidlib.Header;
+import ch.boye.httpclientandroidlib.HeaderElement;
+import ch.boye.httpclientandroidlib.HttpEntity;
+import ch.boye.httpclientandroidlib.NameValuePair;
+import ch.boye.httpclientandroidlib.annotation.Immutable;
+import ch.boye.httpclientandroidlib.entity.ContentType;
+import ch.boye.httpclientandroidlib.message.BasicHeaderValueParser;
+import ch.boye.httpclientandroidlib.message.BasicNameValuePair;
+import ch.boye.httpclientandroidlib.message.ParserCursor;
+import ch.boye.httpclientandroidlib.protocol.HTTP;
+import ch.boye.httpclientandroidlib.util.CharArrayBuffer;
+import ch.boye.httpclientandroidlib.util.EntityUtils;
+
+/**
+ * A collection of utilities for encoding URLs.
+ *
+ * @since 4.0
+ */
+@Immutable
+public class URLEncodedUtils {
+
+ /**
+ * The default HTML form content type.
+ */
+ public static final String CONTENT_TYPE = "application/x-www-form-urlencoded";
+
+ private static final char QP_SEP_A = '&';
+ private static final char QP_SEP_S = ';';
+ private static final String NAME_VALUE_SEPARATOR = "=";
+
+ /**
+ * Returns a list of {@link NameValuePair NameValuePairs} as built from the URI's query portion. For example, a URI
+ * of http://example.org/path/to/file?a=1&b=2&c=3 would return a list of three NameValuePairs, one for a=1, one for
+ * b=2, and one for c=3. By convention, {@code '&'} and {@code ';'} are accepted as parameter separators.
+ * <p>
+ * This is typically useful while parsing an HTTP PUT.
+ *
+ * This API is currently only used for testing.
+ *
+ * @param uri
+ * URI to parse
+ * @param charset
+ * Charset name to use while parsing the query
+ * @return a list of {@link NameValuePair} as built from the URI's query portion.
+ */
+ public static List <NameValuePair> parse(final URI uri, final String charset) {
+ final String query = uri.getRawQuery();
+ if (query != null && query.length() > 0) {
+ final List<NameValuePair> result = new ArrayList<NameValuePair>();
+ final Scanner scanner = new Scanner(query);
+ parse(result, scanner, QP_SEP_PATTERN, charset);
+ return result;
+ }
+ return Collections.emptyList();
+ }
+
+ /**
+ * Returns a list of {@link NameValuePair NameValuePairs} as parsed from an {@link HttpEntity}. The encoding is
+ * taken from the entity's Content-Encoding header.
+ * <p>
+ * This is typically used while parsing an HTTP POST.
+ *
+ * @param entity
+ * The entity to parse
+ * @return a list of {@link NameValuePair} as built from the URI's query portion.
+ * @throws IOException
+ * If there was an exception getting the entity's data.
+ */
+ public static List <NameValuePair> parse(
+ final HttpEntity entity) throws IOException {
+ final ContentType contentType = ContentType.get(entity);
+ if (contentType != null && contentType.getMimeType().equalsIgnoreCase(CONTENT_TYPE)) {
+ final String content = EntityUtils.toString(entity, Consts.ASCII);
+ if (content != null && content.length() > 0) {
+ Charset charset = contentType.getCharset();
+ if (charset == null) {
+ charset = HTTP.DEF_CONTENT_CHARSET;
+ }
+ return parse(content, charset, QP_SEPS);
+ }
+ }
+ return Collections.emptyList();
+ }
+
+ /**
+ * Returns true if the entity's Content-Type header is
+ * <code>application/x-www-form-urlencoded</code>.
+ */
+ public static boolean isEncoded(final HttpEntity entity) {
+ final Header h = entity.getContentType();
+ if (h != null) {
+ final HeaderElement[] elems = h.getElements();
+ if (elems.length > 0) {
+ final String contentType = elems[0].getName();
+ return contentType.equalsIgnoreCase(CONTENT_TYPE);
+ }
+ }
+ return false;
+ }
+
+ /**
+ * Adds all parameters within the Scanner to the list of <code>parameters</code>, as encoded by
+ * <code>encoding</code>. For example, a scanner containing the string <code>a=1&b=2&c=3</code> would add the
+ * {@link NameValuePair NameValuePairs} a=1, b=2, and c=3 to the list of parameters. By convention, {@code '&'} and
+ * {@code ';'} are accepted as parameter separators.
+ *
+ * @param parameters
+ * List to add parameters to.
+ * @param scanner
+ * Input that contains the parameters to parse.
+ * @param charset
+ * Encoding to use when decoding the parameters.
+ */
+ public static void parse(
+ final List <NameValuePair> parameters,
+ final Scanner scanner,
+ final String charset) {
+ parse(parameters, scanner, QP_SEP_PATTERN, charset);
+ }
+
+ /**
+ * Adds all parameters within the Scanner to the list of
+ * <code>parameters</code>, as encoded by <code>encoding</code>. For
+ * example, a scanner containing the string <code>a=1&b=2&c=3</code> would
+ * add the {@link NameValuePair NameValuePairs} a=1, b=2, and c=3 to the
+ * list of parameters.
+ *
+ * @param parameters
+ * List to add parameters to.
+ * @param scanner
+ * Input that contains the parameters to parse.
+ * @param parameterSepartorPattern
+ * The Pattern string for parameter separators, by convention {@code "[&;]"}
+ * @param charset
+ * Encoding to use when decoding the parameters.
+ */
+ public static void parse(
+ final List <NameValuePair> parameters,
+ final Scanner scanner,
+ final String parameterSepartorPattern,
+ final String charset) {
+ scanner.useDelimiter(parameterSepartorPattern);
+ while (scanner.hasNext()) {
+ String name = null;
+ String value = null;
+ final String token = scanner.next();
+ final int i = token.indexOf(NAME_VALUE_SEPARATOR);
+ if (i != -1) {
+ name = decodeFormFields(token.substring(0, i).trim(), charset);
+ value = decodeFormFields(token.substring(i + 1).trim(), charset);
+ } else {
+ name = decodeFormFields(token.trim(), charset);
+ }
+ parameters.add(new BasicNameValuePair(name, value));
+ }
+ }
+
+ /**
+ * Query parameter separators.
+ */
+ private static final char[] QP_SEPS = new char[] { QP_SEP_A, QP_SEP_S };
+
+ /**
+ * Query parameter separator pattern.
+ */
+ private static final String QP_SEP_PATTERN = "[" + new String(QP_SEPS) + "]";
+
+ /**
+ * Returns a list of {@link NameValuePair NameValuePairs} as parsed from the given string using the given character
+ * encoding. By convention, {@code '&'} and {@code ';'} are accepted as parameter separators.
+ *
+ * @param s
+ * text to parse.
+ * @param charset
+ * Encoding to use when decoding the parameters.
+ * @return a list of {@link NameValuePair} as built from the URI's query portion.
+ *
+ * @since 4.2
+ */
+ public static List<NameValuePair> parse(final String s, final Charset charset) {
+ return parse(s, charset, QP_SEPS);
+ }
+
+ /**
+ * Returns a list of {@link NameValuePair NameValuePairs} as parsed from the given string using the given character
+ * encoding.
+ *
+ * @param s
+ * text to parse.
+ * @param charset
+ * Encoding to use when decoding the parameters.
+ * @param parameterSeparator
+ * The characters used to separate parameters, by convention, {@code '&'} and {@code ';'}.
+ * @return a list of {@link NameValuePair} as built from the URI's query portion.
+ *
+ * @since 4.3
+ */
+ public static List<NameValuePair> parse(final String s, final Charset charset, final char... parameterSeparator) {
+ if (s == null) {
+ return Collections.emptyList();
+ }
+ final BasicHeaderValueParser parser = BasicHeaderValueParser.INSTANCE;
+ final CharArrayBuffer buffer = new CharArrayBuffer(s.length());
+ buffer.append(s);
+ final ParserCursor cursor = new ParserCursor(0, buffer.length());
+ final List<NameValuePair> list = new ArrayList<NameValuePair>();
+ while (!cursor.atEnd()) {
+ final NameValuePair nvp = parser.parseNameValuePair(buffer, cursor, parameterSeparator);
+ if (nvp.getName().length() > 0) {
+ list.add(new BasicNameValuePair(
+ decodeFormFields(nvp.getName(), charset),
+ decodeFormFields(nvp.getValue(), charset)));
+ }
+ }
+ return list;
+ }
+
+ /**
+ * Returns a String that is suitable for use as an {@code application/x-www-form-urlencoded}
+ * list of parameters in an HTTP PUT or HTTP POST.
+ *
+ * @param parameters The parameters to include.
+ * @param charset The encoding to use.
+ * @return An {@code application/x-www-form-urlencoded} string
+ */
+ public static String format(
+ final List <? extends NameValuePair> parameters,
+ final String charset) {
+ return format(parameters, QP_SEP_A, charset);
+ }
+
+ /**
+ * Returns a String that is suitable for use as an {@code application/x-www-form-urlencoded}
+ * list of parameters in an HTTP PUT or HTTP POST.
+ *
+ * @param parameters The parameters to include.
+ * @param parameterSeparator The parameter separator, by convention, {@code '&'} or {@code ';'}.
+ * @param charset The encoding to use.
+ * @return An {@code application/x-www-form-urlencoded} string
+ *
+ * @since 4.3
+ */
+ public static String format(
+ final List <? extends NameValuePair> parameters,
+ final char parameterSeparator,
+ final String charset) {
+ final StringBuilder result = new StringBuilder();
+ for (final NameValuePair parameter : parameters) {
+ final String encodedName = encodeFormFields(parameter.getName(), charset);
+ final String encodedValue = encodeFormFields(parameter.getValue(), charset);
+ if (result.length() > 0) {
+ result.append(parameterSeparator);
+ }
+ result.append(encodedName);
+ if (encodedValue != null) {
+ result.append(NAME_VALUE_SEPARATOR);
+ result.append(encodedValue);
+ }
+ }
+ return result.toString();
+ }
+
+ /**
+ * Returns a String that is suitable for use as an {@code application/x-www-form-urlencoded}
+ * list of parameters in an HTTP PUT or HTTP POST.
+ *
+ * @param parameters The parameters to include.
+ * @param charset The encoding to use.
+ * @return An {@code application/x-www-form-urlencoded} string
+ *
+ * @since 4.2
+ */
+ public static String format(
+ final Iterable<? extends NameValuePair> parameters,
+ final Charset charset) {
+ return format(parameters, QP_SEP_A, charset);
+ }
+
+ /**
+ * Returns a String that is suitable for use as an {@code application/x-www-form-urlencoded}
+ * list of parameters in an HTTP PUT or HTTP POST.
+ *
+ * @param parameters The parameters to include.
+ * @param parameterSeparator The parameter separator, by convention, {@code '&'} or {@code ';'}.
+ * @param charset The encoding to use.
+ * @return An {@code application/x-www-form-urlencoded} string
+ *
+ * @since 4.3
+ */
+ public static String format(
+ final Iterable<? extends NameValuePair> parameters,
+ final char parameterSeparator,
+ final Charset charset) {
+ final StringBuilder result = new StringBuilder();
+ for (final NameValuePair parameter : parameters) {
+ final String encodedName = encodeFormFields(parameter.getName(), charset);
+ final String encodedValue = encodeFormFields(parameter.getValue(), charset);
+ if (result.length() > 0) {
+ result.append(parameterSeparator);
+ }
+ result.append(encodedName);
+ if (encodedValue != null) {
+ result.append(NAME_VALUE_SEPARATOR);
+ result.append(encodedValue);
+ }
+ }
+ return result.toString();
+ }
+
+ /**
+ * Unreserved characters, i.e. alphanumeric, plus: {@code _ - ! . ~ ' ( ) *}
+ * <p>
+ * This list is the same as the {@code unreserved} list in
+ * <a href="http://www.ietf.org/rfc/rfc2396.txt">RFC 2396</a>
+ */
+ private static final BitSet UNRESERVED = new BitSet(256);
+ /**
+ * Punctuation characters: , ; : $ & + =
+ * <p>
+ * These are the additional characters allowed by userinfo.
+ */
+ private static final BitSet PUNCT = new BitSet(256);
+ /** Characters which are safe to use in userinfo,
+ * i.e. {@link #UNRESERVED} plus {@link #PUNCT}uation */
+ private static final BitSet USERINFO = new BitSet(256);
+ /** Characters which are safe to use in a path,
+ * i.e. {@link #UNRESERVED} plus {@link #PUNCT}uation plus / @ */
+ private static final BitSet PATHSAFE = new BitSet(256);
+ /** Characters which are safe to use in a query or a fragment,
+ * i.e. {@link #RESERVED} plus {@link #UNRESERVED} */
+ private static final BitSet URIC = new BitSet(256);
+
+ /**
+ * Reserved characters, i.e. {@code ;/?:@&=+$,[]}
+ * <p>
+ * This list is the same as the {@code reserved} list in
+ * <a href="http://www.ietf.org/rfc/rfc2396.txt">RFC 2396</a>
+ * as augmented by
+ * <a href="http://www.ietf.org/rfc/rfc2732.txt">RFC 2732</a>
+ */
+ private static final BitSet RESERVED = new BitSet(256);
+
+
+ /**
+ * Safe characters for x-www-form-urlencoded data, as per java.net.URLEncoder and browser behaviour,
+ * i.e. alphanumeric plus {@code "-", "_", ".", "*"}
+ */
+ private static final BitSet URLENCODER = new BitSet(256);
+
+ static {
+ // unreserved chars
+ // alpha characters
+ for (int i = 'a'; i <= 'z'; i++) {
+ UNRESERVED.set(i);
+ }
+ for (int i = 'A'; i <= 'Z'; i++) {
+ UNRESERVED.set(i);
+ }
+ // numeric characters
+ for (int i = '0'; i <= '9'; i++) {
+ UNRESERVED.set(i);
+ }
+ UNRESERVED.set('_'); // these are the charactes of the "mark" list
+ UNRESERVED.set('-');
+ UNRESERVED.set('.');
+ UNRESERVED.set('*');
+ URLENCODER.or(UNRESERVED); // skip remaining unreserved characters
+ UNRESERVED.set('!');
+ UNRESERVED.set('~');
+ UNRESERVED.set('\'');
+ UNRESERVED.set('(');
+ UNRESERVED.set(')');
+ // punct chars
+ PUNCT.set(',');
+ PUNCT.set(';');
+ PUNCT.set(':');
+ PUNCT.set('$');
+ PUNCT.set('&');
+ PUNCT.set('+');
+ PUNCT.set('=');
+ // Safe for userinfo
+ USERINFO.or(UNRESERVED);
+ USERINFO.or(PUNCT);
+
+ // URL path safe
+ PATHSAFE.or(UNRESERVED);
+ PATHSAFE.set('/'); // segment separator
+ PATHSAFE.set(';'); // param separator
+ PATHSAFE.set(':'); // rest as per list in 2396, i.e. : @ & = + $ ,
+ PATHSAFE.set('@');
+ PATHSAFE.set('&');
+ PATHSAFE.set('=');
+ PATHSAFE.set('+');
+ PATHSAFE.set('$');
+ PATHSAFE.set(',');
+
+ RESERVED.set(';');
+ RESERVED.set('/');
+ RESERVED.set('?');
+ RESERVED.set(':');
+ RESERVED.set('@');
+ RESERVED.set('&');
+ RESERVED.set('=');
+ RESERVED.set('+');
+ RESERVED.set('$');
+ RESERVED.set(',');
+ RESERVED.set('['); // added by RFC 2732
+ RESERVED.set(']'); // added by RFC 2732
+
+ URIC.or(RESERVED);
+ URIC.or(UNRESERVED);
+ }
+
+ private static final int RADIX = 16;
+
+ private static String urlEncode(
+ final String content,
+ final Charset charset,
+ final BitSet safechars,
+ final boolean blankAsPlus) {
+ if (content == null) {
+ return null;
+ }
+ final StringBuilder buf = new StringBuilder();
+ final ByteBuffer bb = charset.encode(content);
+ while (bb.hasRemaining()) {
+ final int b = bb.get() & 0xff;
+ if (safechars.get(b)) {
+ buf.append((char) b);
+ } else if (blankAsPlus && b == ' ') {
+ buf.append('+');
+ } else {
+ buf.append("%");
+ final char hex1 = Character.toUpperCase(Character.forDigit((b >> 4) & 0xF, RADIX));
+ final char hex2 = Character.toUpperCase(Character.forDigit(b & 0xF, RADIX));
+ buf.append(hex1);
+ buf.append(hex2);
+ }
+ }
+ return buf.toString();
+ }
+
+ /**
+ * Decode/unescape a portion of a URL, to use with the query part ensure {@code plusAsBlank} is true.
+ *
+ * @param content the portion to decode
+ * @param charset the charset to use
+ * @param plusAsBlank if {@code true}, then convert '+' to space (e.g. for www-url-form-encoded content), otherwise leave as is.
+ * @return encoded string
+ */
+ private static String urlDecode(
+ final String content,
+ final Charset charset,
+ final boolean plusAsBlank) {
+ if (content == null) {
+ return null;
+ }
+ final ByteBuffer bb = ByteBuffer.allocate(content.length());
+ final CharBuffer cb = CharBuffer.wrap(content);
+ while (cb.hasRemaining()) {
+ final char c = cb.get();
+ if (c == '%' && cb.remaining() >= 2) {
+ final char uc = cb.get();
+ final char lc = cb.get();
+ final int u = Character.digit(uc, 16);
+ final int l = Character.digit(lc, 16);
+ if (u != -1 && l != -1) {
+ bb.put((byte) ((u << 4) + l));
+ } else {
+ bb.put((byte) '%');
+ bb.put((byte) uc);
+ bb.put((byte) lc);
+ }
+ } else if (plusAsBlank && c == '+') {
+ bb.put((byte) ' ');
+ } else {
+ bb.put((byte) c);
+ }
+ }
+ bb.flip();
+ return charset.decode(bb).toString();
+ }
+
+ /**
+ * Decode/unescape www-url-form-encoded content.
+ *
+ * @param content the content to decode, will decode '+' as space
+ * @param charset the charset to use
+ * @return encoded string
+ */
+ private static String decodeFormFields (final String content, final String charset) {
+ if (content == null) {
+ return null;
+ }
+ return urlDecode(content, charset != null ? Charset.forName(charset) : Consts.UTF_8, true);
+ }
+
+ /**
+ * Decode/unescape www-url-form-encoded content.
+ *
+ * @param content the content to decode, will decode '+' as space
+ * @param charset the charset to use
+ * @return encoded string
+ */
+ private static String decodeFormFields (final String content, final Charset charset) {
+ if (content == null) {
+ return null;
+ }
+ return urlDecode(content, charset != null ? charset : Consts.UTF_8, true);
+ }
+
+ /**
+ * Encode/escape www-url-form-encoded content.
+ * <p>
+ * Uses the {@link #URLENCODER} set of characters, rather than
+ * the {@link #UNRSERVED} set; this is for compatibilty with previous
+ * releases, URLEncoder.encode() and most browsers.
+ *
+ * @param content the content to encode, will convert space to '+'
+ * @param charset the charset to use
+ * @return encoded string
+ */
+ private static String encodeFormFields(final String content, final String charset) {
+ if (content == null) {
+ return null;
+ }
+ return urlEncode(content, charset != null ? Charset.forName(charset) : Consts.UTF_8, URLENCODER, true);
+ }
+
+ /**
+ * Encode/escape www-url-form-encoded content.
+ * <p>
+ * Uses the {@link #URLENCODER} set of characters, rather than
+ * the {@link #UNRSERVED} set; this is for compatibilty with previous
+ * releases, URLEncoder.encode() and most browsers.
+ *
+ * @param content the content to encode, will convert space to '+'
+ * @param charset the charset to use
+ * @return encoded string
+ */
+ private static String encodeFormFields (final String content, final Charset charset) {
+ if (content == null) {
+ return null;
+ }
+ return urlEncode(content, charset != null ? charset : Consts.UTF_8, URLENCODER, true);
+ }
+
+ /**
+ * Encode a String using the {@link #USERINFO} set of characters.
+ * <p>
+ * Used by URIBuilder to encode the userinfo segment.
+ *
+ * @param content the string to encode, does not convert space to '+'
+ * @param charset the charset to use
+ * @return the encoded string
+ */
+ static String encUserInfo(final String content, final Charset charset) {
+ return urlEncode(content, charset, USERINFO, false);
+ }
+
+ /**
+ * Encode a String using the {@link #URIC} set of characters.
+ * <p>
+ * Used by URIBuilder to encode the query and fragment segments.
+ *
+ * @param content the string to encode, does not convert space to '+'
+ * @param charset the charset to use
+ * @return the encoded string
+ */
+ static String encUric(final String content, final Charset charset) {
+ return urlEncode(content, charset, URIC, false);
+ }
+
+ /**
+ * Encode a String using the {@link #PATHSAFE} set of characters.
+ * <p>
+ * Used by URIBuilder to encode path segments.
+ *
+ * @param content the string to encode, does not convert space to '+'
+ * @param charset the charset to use
+ * @return the encoded string
+ */
+ static String encPath(final String content, final Charset charset) {
+ return urlEncode(content, charset, PATHSAFE, false);
+ }
+
+}
diff --git a/mobile/android/thirdparty/ch/boye/httpclientandroidlib/client/utils/package-info.java b/mobile/android/thirdparty/ch/boye/httpclientandroidlib/client/utils/package-info.java
new file mode 100644
index 000000000..7f5671654
--- /dev/null
+++ b/mobile/android/thirdparty/ch/boye/httpclientandroidlib/client/utils/package-info.java
@@ -0,0 +1,31 @@
+/*
+ * ====================================================================
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ * ====================================================================
+ *
+ * This software consists of voluntary contributions made by many
+ * individuals on behalf of the Apache Software Foundation. For more
+ * information on the Apache Software Foundation, please see
+ * <http://www.apache.org/>.
+ *
+ */
+
+/**
+ * Client utility classes.
+ */
+package ch.boye.httpclientandroidlib.client.utils;