mirror of
https://repo.dactyloidae.xyz/Dactyloidae/UXP.git
synced 2026-09-07 16:28:38 +09:00
Issue #1053 - Drop support Android and remove Fennec - Part 1a: Remove mobile/android
This commit is contained in:
parent
85045bf6be
commit
c9b411d6cd
3891 changed files with 0 additions and 428084 deletions
|
|
@ -1,86 +0,0 @@
|
|||
/*
|
||||
* ====================================================================
|
||||
* 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() {
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -1,250 +0,0 @@
|
|||
/*
|
||||
* ====================================================================
|
||||
* 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();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -1,149 +0,0 @@
|
|||
/*
|
||||
* ====================================================================
|
||||
* 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) {
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -1,42 +0,0 @@
|
|||
/*
|
||||
* ====================================================================
|
||||
* 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);
|
||||
}
|
||||
|
|
@ -1,71 +0,0 @@
|
|||
/*
|
||||
* ====================================================================
|
||||
* 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);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -1,54 +0,0 @@
|
|||
/*
|
||||
* ====================================================================
|
||||
* 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);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -1,141 +0,0 @@
|
|||
/*
|
||||
* ====================================================================
|
||||
* 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();
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -1,490 +0,0 @@
|
|||
/*
|
||||
* ====================================================================
|
||||
* 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;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -1,428 +0,0 @@
|
|||
/*
|
||||
* ====================================================================
|
||||
* 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 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() {
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -1,628 +0,0 @@
|
|||
/*
|
||||
* ====================================================================
|
||||
* 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);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -1,31 +0,0 @@
|
|||
/*
|
||||
* ====================================================================
|
||||
* 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;
|
||||
Loading…
Add table
Add a link
Reference in a new issue