Package org.restlet.client.engine.header

Source Code of org.restlet.client.engine.header.HeaderUtils

/**
* Copyright 2005-2012 Restlet S.A.S.
*
* The contents of this file are subject to the terms of one of the following
* open source licenses: Apache 2.0 or LGPL 3.0 or LGPL 2.1 or CDDL 1.0 or EPL
* 1.0 (the "Licenses"). You can select the license that you prefer but you may
* not use this file except in compliance with one of these Licenses.
*
* You can obtain a copy of the Apache 2.0 license at
* http://www.opensource.org/licenses/apache-2.0
*
* You can obtain a copy of the LGPL 3.0 license at
* http://www.opensource.org/licenses/lgpl-3.0
*
* You can obtain a copy of the LGPL 2.1 license at
* http://www.opensource.org/licenses/lgpl-2.1
*
* You can obtain a copy of the CDDL 1.0 license at
* http://www.opensource.org/licenses/cddl1
*
* You can obtain a copy of the EPL 1.0 license at
* http://www.opensource.org/licenses/eclipse-1.0
*
* See the Licenses for the specific language governing permissions and
* limitations under the Licenses.
*
* Alternatively, you can obtain a royalty free commercial license with less
* limitations, transferable or non-transferable, directly at
* http://www.restlet.com/products/restlet-framework
*
* Restlet is a registered trademark of Restlet S.A.S.
*/

package org.restlet.client.engine.header;

import java.io.IOException;
import java.io.OutputStream;
import java.util.Arrays;
import java.util.Collections;
import java.util.Date;
import java.util.List;
import java.util.Set;
import java.util.logging.Level;

import org.restlet.client.Context;
import org.restlet.client.Message;
import org.restlet.client.Request;
import org.restlet.client.Response;
import org.restlet.client.data.AuthenticationInfo;
import org.restlet.client.data.ChallengeRequest;
import org.restlet.client.data.ChallengeResponse;
import org.restlet.client.data.ClientInfo;
import org.restlet.client.data.Conditions;
import org.restlet.client.data.CookieSetting;
import org.restlet.client.data.Digest;
import org.restlet.client.data.Disposition;
import org.restlet.client.data.MediaType;
import org.restlet.client.data.Method;
import org.restlet.client.data.Reference;
import org.restlet.client.data.Status;
import org.restlet.client.data.Tag;
import org.restlet.client.engine.Engine;
import org.restlet.client.engine.util.CaseInsensitiveHashSet;
import org.restlet.client.engine.util.DateUtils;
import org.restlet.client.engine.util.StringUtils;
import org.restlet.client.representation.EmptyRepresentation;
import org.restlet.client.representation.Representation;
import org.restlet.client.util.Series;

/**
* HTTP-style header utilities.
*
* @author Jerome Louvel
*/
public class HeaderUtils {

    /**
     * Standard set of headers which cannot be modified.
     */
    private static final Set<String> STANDARD_HEADERS = Collections
            .unmodifiableSet(new CaseInsensitiveHashSet(Arrays.asList(
                    HeaderConstants.HEADER_ACCEPT,
                    HeaderConstants.HEADER_ACCEPT_CHARSET,
                    HeaderConstants.HEADER_ACCEPT_ENCODING,
                    HeaderConstants.HEADER_ACCEPT_LANGUAGE,
                    HeaderConstants.HEADER_ACCEPT_RANGES,
                    HeaderConstants.HEADER_AGE, HeaderConstants.HEADER_ALLOW,
                    HeaderConstants.HEADER_AUTHENTICATION_INFO,
                    HeaderConstants.HEADER_AUTHORIZATION,
                    HeaderConstants.HEADER_CACHE_CONTROL,
                    HeaderConstants.HEADER_CONNECTION,
                    HeaderConstants.HEADER_CONTENT_DISPOSITION,
                    HeaderConstants.HEADER_CONTENT_ENCODING,
                    HeaderConstants.HEADER_CONTENT_LANGUAGE,
                    HeaderConstants.HEADER_CONTENT_LENGTH,
                    HeaderConstants.HEADER_CONTENT_LOCATION,
                    HeaderConstants.HEADER_CONTENT_MD5,
                    HeaderConstants.HEADER_CONTENT_RANGE,
                    HeaderConstants.HEADER_CONTENT_TYPE,
                    HeaderConstants.HEADER_COOKIE, HeaderConstants.HEADER_DATE,
                    HeaderConstants.HEADER_ETAG, HeaderConstants.HEADER_EXPECT,
                    HeaderConstants.HEADER_EXPIRES,
                    HeaderConstants.HEADER_FROM, HeaderConstants.HEADER_HOST,
                    HeaderConstants.HEADER_IF_MATCH,
                    HeaderConstants.HEADER_IF_MODIFIED_SINCE,
                    HeaderConstants.HEADER_IF_NONE_MATCH,
                    HeaderConstants.HEADER_IF_RANGE,
                    HeaderConstants.HEADER_IF_UNMODIFIED_SINCE,
                    HeaderConstants.HEADER_LAST_MODIFIED,
                    HeaderConstants.HEADER_LOCATION,
                    HeaderConstants.HEADER_MAX_FORWARDS,
                    HeaderConstants.HEADER_PROXY_AUTHENTICATE,
                    HeaderConstants.HEADER_PROXY_AUTHORIZATION,
                    HeaderConstants.HEADER_RANGE,
                    HeaderConstants.HEADER_REFERRER,
                    HeaderConstants.HEADER_RETRY_AFTER,
                    HeaderConstants.HEADER_SERVER,
                    HeaderConstants.HEADER_SET_COOKIE,
                    HeaderConstants.HEADER_SET_COOKIE2,
                    HeaderConstants.HEADER_USER_AGENT,
                    HeaderConstants.HEADER_VARY, HeaderConstants.HEADER_VIA,
                    HeaderConstants.HEADER_WARNING,
                    HeaderConstants.HEADER_WWW_AUTHENTICATE)));

    /**
     * Set of unsupported headers that will be covered in future versions.
     */
    private static final Set<String> UNSUPPORTED_STANDARD_HEADERS = Collections
            .unmodifiableSet(new CaseInsensitiveHashSet(Arrays.asList(
                    HeaderConstants.HEADER_PRAGMA,
                    HeaderConstants.HEADER_TRAILER,
                    HeaderConstants.HEADER_TRANSFER_ENCODING,
                    HeaderConstants.HEADER_TRANSFER_EXTENSION,
                    HeaderConstants.HEADER_UPGRADE)));

    /**
     * Adds the entity headers based on the {@link Representation} to the
     * {@link Series}.
     *
     * @param entity
     *            The source entity {@link Representation}.
     * @param headers
     *            The target headers {@link Series}.
     */
    public static void addEntityHeaders(Representation entity,
            Series<Header> headers) {
        if (entity == null || !entity.isAvailable()) {
            addHeader(HeaderConstants.HEADER_CONTENT_LENGTH, "0", headers);
        } else if (entity.getAvailableSize() != Representation.UNKNOWN_SIZE) {
            addHeader(HeaderConstants.HEADER_CONTENT_LENGTH,
                    Long.toString(entity.getAvailableSize()), headers);
        }

        if (entity != null) {
            addHeader(HeaderConstants.HEADER_CONTENT_ENCODING,
                    EncodingWriter.write(entity.getEncodings()), headers);
            addHeader(HeaderConstants.HEADER_CONTENT_LANGUAGE,
                    LanguageWriter.write(entity.getLanguages()), headers);

            if (entity.getLocationRef() != null) {
                addHeader(HeaderConstants.HEADER_CONTENT_LOCATION, entity
                        .getLocationRef().getTargetRef().toString(), headers);
            }


            if (entity.getRange() != null) {
                addHeader(HeaderConstants.HEADER_CONTENT_RANGE,
                        RangeWriter.write(entity.getRange(), entity.getSize()),
                        headers);
            }

            if (entity.getMediaType() != null) {
                addHeader(HeaderConstants.HEADER_CONTENT_TYPE,
                        ContentType.writeHeader(entity), headers);
            }

            if (entity.getExpirationDate() != null) {
                addHeader(HeaderConstants.HEADER_EXPIRES,
                        DateWriter.write(entity.getExpirationDate()), headers);
            }

            if (entity.getModificationDate() != null) {
                addHeader(HeaderConstants.HEADER_LAST_MODIFIED,
                        DateWriter.write(entity.getModificationDate()), headers);
            }

            if (entity.getTag() != null) {
                addHeader(HeaderConstants.HEADER_ETAG,
                        TagWriter.write(entity.getTag()), headers);
            }

            if (entity.getDisposition() != null
                    && !Disposition.TYPE_NONE.equals(entity.getDisposition()
                            .getType())) {
                addHeader(HeaderConstants.HEADER_CONTENT_DISPOSITION,
                        DispositionWriter.write(entity.getDisposition()),
                        headers);
            }
        }
    }

    /**
     * Adds extension headers if they are non-standard headers.
     *
     * @param existingHeaders
     *            The headers to update.
     * @param additionalHeaders
     *            The headers to add.
     */
    public static void addExtensionHeaders(Series<Header> existingHeaders,
            Series<Header> additionalHeaders) {
        if (additionalHeaders != null) {
            for (Header param : additionalHeaders) {
                if (STANDARD_HEADERS.contains(param.getName())) {
                    // Standard headers that can't be overridden
                    Context.getCurrentLogger()
                            .warning(
                                    "Addition of the standard header \""
                                            + param.getName()
                                            + "\" is not allowed. Please use the equivalent property in the Restlet API.");
                } else if (UNSUPPORTED_STANDARD_HEADERS.contains(param
                        .getName())) {
                    Context.getCurrentLogger()
                            .warning(
                                    "Addition of the standard header \""
                                            + param.getName()
                                            + "\" is discouraged as a future version of the Restlet API will directly support it.");
                    existingHeaders.add(param);
                } else {
                    existingHeaders.add(param);
                }
            }
        }
    }

    /**
     * Adds the general headers from the {@link Message} to the {@link Series}.
     *
     * @param message
     *            The source {@link Message}.
     * @param headers
     *            The target headers {@link Series}.
     */
    public static void addGeneralHeaders(Message message, Series<Header> headers) {
        addHeader(HeaderConstants.HEADER_CACHE_CONTROL,
                CacheDirectiveWriter.write(message.getCacheDirectives()),
                headers);

        if (message.getDate() == null) {
            message.setDate(new Date());
        }

        addHeader(HeaderConstants.HEADER_DATE,
                DateWriter.write(message.getDate()), headers);

        addHeader(HeaderConstants.HEADER_VIA,
                RecipientInfoWriter.write(message.getRecipientsInfo()), headers);

        addHeader(HeaderConstants.HEADER_WARNING,
                WarningWriter.write(message.getWarnings()), headers);
    }

    /**
     * Adds a header to the given list. Checks for exceptions and logs them.
     *
     * @param headerName
     *            The header name.
     * @param headerValue
     *            The header value.
     * @param headers
     *            The headers list.
     */
    public static void addHeader(String headerName, String headerValue,
            Series<Header> headers) {
        if ((headerName != null) && (headerValue != null)
                && (headerValue.length() > 0)) {
            try {
                headers.add(headerName, headerValue);
            } catch (Throwable t) {
                Context.getCurrentLogger().log(Level.WARNING,
                        "Unable to format the " + headerName + " header", t);
            }
        }
    }

    /**
     * Adds the entity headers based on the {@link Representation} to the
     * {@link Series} when a 304 (Not Modified) status is returned.
     *
     * @param entity
     *            The source entity {@link Representation}.
     * @param headers
     *            The target headers {@link Series}.
     */
    public static void addNotModifiedEntityHeaders(Representation entity,
            Series<Header> headers) {
        if (entity != null) {
            if (entity.getTag() != null) {
                HeaderUtils.addHeader(HeaderConstants.HEADER_ETAG,
                        TagWriter.write(entity.getTag()), headers);
            }

            if (entity.getLocationRef() != null) {
                HeaderUtils.addHeader(HeaderConstants.HEADER_CONTENT_LOCATION,
                        entity.getLocationRef().getTargetRef().toString(),
                        headers);
            }
        }
    }

    /**
     * Adds the headers based on the {@link Request} to the given {@link Series}
     * .
     *
     * @param request
     *            The {@link Request} to copy the headers from.
     * @param headers
     *            The {@link Series} to copy the headers to.
     */
    @SuppressWarnings("unchecked")
    public static void addRequestHeaders(Request request, Series<Header> headers) {
        ClientInfo clientInfo = request.getClientInfo();

        if (!clientInfo.getAcceptedMediaTypes().isEmpty()) {
            addHeader(HeaderConstants.HEADER_ACCEPT,
                    PreferenceWriter.write(clientInfo.getAcceptedMediaTypes()),
                    headers);
        } else {
            addHeader(HeaderConstants.HEADER_ACCEPT, MediaType.ALL.getName(),
                    headers);
        }

        if (!clientInfo.getAcceptedCharacterSets().isEmpty()) {
            addHeader(HeaderConstants.HEADER_ACCEPT_CHARSET,
                    PreferenceWriter.write(clientInfo
                            .getAcceptedCharacterSets()), headers);
        }

        if (!clientInfo.getAcceptedEncodings().isEmpty()) {
            addHeader(HeaderConstants.HEADER_ACCEPT_ENCODING,
                    PreferenceWriter.write(clientInfo.getAcceptedEncodings()),
                    headers);
        }

        if (!clientInfo.getAcceptedLanguages().isEmpty()) {
            addHeader(HeaderConstants.HEADER_ACCEPT_LANGUAGE,
                    PreferenceWriter.write(clientInfo.getAcceptedLanguages()),
                    headers);
        }


        if (clientInfo.getFrom() != null) {
            addHeader(HeaderConstants.HEADER_FROM, request.getClientInfo()
                    .getFrom(), headers);
        }

        // Manually add the host name and port when it is potentially
        // different from the one specified in the target resource reference.
        Reference hostRef = (request.getResourceRef().getBaseRef() != null) ? request
                .getResourceRef().getBaseRef() : request.getResourceRef();

        if (hostRef.getHostDomain() != null) {
            String host = hostRef.getHostDomain();
            int hostRefPortValue = hostRef.getHostPort();

            if ((hostRefPortValue != -1)
                    && (hostRefPortValue != request.getProtocol()
                            .getDefaultPort())) {
                host = host + ':' + hostRefPortValue;
            }

            addHeader(HeaderConstants.HEADER_HOST, host, headers);
        }

        Conditions conditions = request.getConditions();
        addHeader(HeaderConstants.HEADER_IF_MATCH,
                TagWriter.write(conditions.getMatch()), headers);
        addHeader(HeaderConstants.HEADER_IF_NONE_MATCH,
                TagWriter.write(conditions.getNoneMatch()), headers);

        if (conditions.getModifiedSince() != null) {
            addHeader(HeaderConstants.HEADER_IF_MODIFIED_SINCE,
                    DateWriter.write(conditions.getModifiedSince()), headers);
        }

        if (conditions.getRangeTag() != null
                && conditions.getRangeDate() != null) {
            Context.getCurrentLogger()
                    .log(Level.WARNING,
                            "Unable to format the HTTP If-Range header due to the presence of both entity tag and modification date.");
        } else if (conditions.getRangeTag() != null) {
            addHeader(HeaderConstants.HEADER_IF_RANGE,
                    TagWriter.write(conditions.getRangeTag()), headers);
        } else if (conditions.getRangeDate() != null) {
            addHeader(HeaderConstants.HEADER_IF_RANGE,
                    DateWriter.write(conditions.getRangeDate()), headers);
        }

        if (conditions.getUnmodifiedSince() != null) {
            addHeader(HeaderConstants.HEADER_IF_UNMODIFIED_SINCE,
                    DateWriter.write(conditions.getUnmodifiedSince()), headers);
        }

        if (request.getMaxForwards() > -1) {
            addHeader(HeaderConstants.HEADER_MAX_FORWARDS,
                    Integer.toString(request.getMaxForwards()), headers);
        }

        if (!request.getRanges().isEmpty()) {
            addHeader(HeaderConstants.HEADER_RANGE,
                    RangeWriter.write(request.getRanges()), headers);
        }

        if (request.getReferrerRef() != null) {
            addHeader(HeaderConstants.HEADER_REFERRER, request.getReferrerRef()
                    .toString(), headers);
        }

        if (request.getClientInfo().getAgent() != null) {
            addHeader(HeaderConstants.HEADER_USER_AGENT, request
                    .getClientInfo().getAgent(), headers);
        }


        // ----------------------------------
        // 3) Add supported extension headers
        // ----------------------------------

        if (request.getCookies().size() > 0) {
            addHeader(HeaderConstants.HEADER_COOKIE,
                    CookieWriter.write(request.getCookies()), headers);
        }

        // -------------------------------------
        // 4) Add user-defined extension headers
        // -------------------------------------
        Series<Header> additionalHeaders = (Series<Header>) request
                .getAttributes().get(HeaderConstants.ATTRIBUTE_HEADERS);
        addExtensionHeaders(headers, additionalHeaders);

        // ---------------------------------------
        // 5) Add authorization headers at the end
        // ---------------------------------------

    }


    /**
     * Copies headers into a response.
     *
     * @param headers
     *            The headers to copy.
     * @param response
     *            The response to update.
     */
    public static void copyResponseTransportHeaders(Series<Header> headers,
            Response response) {
        if (headers != null) {
            for (Header header : headers) {
                if (header.getName().equalsIgnoreCase(
                        HeaderConstants.HEADER_LOCATION)) {
                    response.setLocationRef(header.getValue());
                } else if (header.getName().equalsIgnoreCase(
                        HeaderConstants.HEADER_AGE)) {
                    try {
                        response.setAge(Integer.parseInt(header.getValue()));
                    } catch (NumberFormatException nfe) {
                        Context.getCurrentLogger().log(
                                Level.WARNING,
                                "Error during Age header parsing. Header: "
                                        + header.getValue(), nfe);
                    }
                } else if (header.getName().equalsIgnoreCase(
                        HeaderConstants.HEADER_DATE)) {
                    Date date = DateUtils.parse(header.getValue());

                    if (date == null) {
                        date = new Date();
                    }

                    response.setDate(date);
                } else if (header.getName().equalsIgnoreCase(
                        HeaderConstants.HEADER_RETRY_AFTER)) {
                } else if ((header.getName()
                        .equalsIgnoreCase(HeaderConstants.HEADER_SET_COOKIE))
                        || (header.getName()
                                .equalsIgnoreCase(HeaderConstants.HEADER_SET_COOKIE2))) {
                    try {
                        CookieSettingReader cr = new CookieSettingReader(
                                header.getValue());
                        response.getCookieSettings().add(cr.readValue());
                    } catch (Exception e) {
                        Context.getCurrentLogger().log(
                                Level.WARNING,
                                "Error during cookie setting parsing. Header: "
                                        + header.getValue(), e);
                    }
                } else if (header.getName().equalsIgnoreCase(
                        HeaderConstants.HEADER_WWW_AUTHENTICATE)) {
                } else if (header.getName().equalsIgnoreCase(
                        HeaderConstants.HEADER_PROXY_AUTHENTICATE)) {
                } else if (header.getName().equalsIgnoreCase(
                        HeaderConstants.HEADER_AUTHENTICATION_INFO)) {
                } else if (header.getName().equalsIgnoreCase(
                        HeaderConstants.HEADER_SERVER)) {
                    response.getServerInfo().setAgent(header.getValue());
                } else if (header.getName().equalsIgnoreCase(
                        HeaderConstants.HEADER_ALLOW)) {
                    MethodReader
                            .addValues(header, response.getAllowedMethods());
                } else if (header.getName().equalsIgnoreCase(
                        HeaderConstants.HEADER_VARY)) {
                    DimensionReader.addValues(header, response.getDimensions());
                } else if (header.getName().equalsIgnoreCase(
                        HeaderConstants.HEADER_VIA)) {
                    RecipientInfoReader.addValues(header,
                            response.getRecipientsInfo());
                } else if (header.getName().equalsIgnoreCase(
                        HeaderConstants.HEADER_WARNING)) {
                    WarningReader.addValues(header, response.getWarnings());
                } else if (header.getName().equalsIgnoreCase(
                        HeaderConstants.HEADER_CACHE_CONTROL)) {
                    CacheDirectiveReader.addValues(header,
                            response.getCacheDirectives());
                } else if (header.getName().equalsIgnoreCase(
                        HeaderConstants.HEADER_ACCEPT_RANGES)) {
                    TokenReader tr = new TokenReader(header.getValue());
                    response.getServerInfo().setAcceptingRanges(
                            tr.readValues().contains("bytes"));
                }
            }
        }
    }

    /**
     * Extracts entity headers and updates a given representation or create an
     * empty one when at least one entity header is present.
     *
     * @param headers
     *            The headers to copy.
     * @param representation
     *            The representation to update or null.
     * @return a representation updated with the given entity headers.
     * @throws NumberFormatException
     * @see HeaderUtils#copyResponseTransportHeaders(Series, Response)
     */
    public static Representation extractEntityHeaders(Iterable<Header> headers,
            Representation representation) throws NumberFormatException {
        Representation result = (representation == null) ? new EmptyRepresentation()
                : representation;
        boolean entityHeaderFound = false;

        if (headers != null) {
            for (Header header : headers) {
                if (header.getName().equalsIgnoreCase(
                        HeaderConstants.HEADER_CONTENT_TYPE)) {
                    ContentType contentType = new ContentType(header.getValue());
                    result.setMediaType(contentType.getMediaType());

                    if ((result.getCharacterSet() == null)
                            || (contentType.getCharacterSet() != null)) {
                        result.setCharacterSet(contentType.getCharacterSet());
                    }

                    entityHeaderFound = true;
                } else if (header.getName().equalsIgnoreCase(
                        HeaderConstants.HEADER_CONTENT_LENGTH)) {
                    entityHeaderFound = true;
                } else if (header.getName().equalsIgnoreCase(
                        HeaderConstants.HEADER_EXPIRES)) {
                    result.setExpirationDate(HeaderReader.readDate(
                            header.getValue(), false));
                    entityHeaderFound = true;
                } else if (header.getName().equalsIgnoreCase(
                        HeaderConstants.HEADER_CONTENT_ENCODING)) {
                    new EncodingReader(header.getValue()).addValues(result
                            .getEncodings());
                    entityHeaderFound = true;
                } else if (header.getName().equalsIgnoreCase(
                        HeaderConstants.HEADER_CONTENT_LANGUAGE)) {
                    new LanguageReader(header.getValue()).addValues(result
                            .getLanguages());
                    entityHeaderFound = true;
                } else if (header.getName().equalsIgnoreCase(
                        HeaderConstants.HEADER_LAST_MODIFIED)) {
                    result.setModificationDate(HeaderReader.readDate(
                            header.getValue(), false));
                    entityHeaderFound = true;
                } else if (header.getName().equalsIgnoreCase(
                        HeaderConstants.HEADER_ETAG)) {
                    result.setTag(Tag.parse(header.getValue()));
                    entityHeaderFound = true;
                } else if (header.getName().equalsIgnoreCase(
                        HeaderConstants.HEADER_CONTENT_LOCATION)) {
                    result.setLocationRef(header.getValue());
                    entityHeaderFound = true;
                } else if (header.getName().equalsIgnoreCase(
                        HeaderConstants.HEADER_CONTENT_DISPOSITION)) {
                    try {
                        result.setDisposition(new DispositionReader(header
                                .getValue()).readValue());
                        entityHeaderFound = true;
                    } catch (IOException ioe) {
                        Context.getCurrentLogger().log(
                                Level.WARNING,
                                "Error during Content-Disposition header parsing. Header: "
                                        + header.getValue(), ioe);
                    }
                } else if (header.getName().equalsIgnoreCase(
                        HeaderConstants.HEADER_CONTENT_RANGE)) {
                } else if (header.getName().equalsIgnoreCase(
                        HeaderConstants.HEADER_CONTENT_MD5)) {
                }
            }
        }

        // If no representation was initially expected and no entity header
        // is found, then do not return any representation
        if ((representation == null) && !entityHeaderFound) {
            result = null;
        }

        return result;
    }

    /**
     * Returns the content length of the request entity if know,
     * {@link Representation#UNKNOWN_SIZE} otherwise.
     *
     * @return The request content length.
     */
    public static long getContentLength(Series<Header> headers) {
        long contentLength = Representation.UNKNOWN_SIZE;

        if (headers != null) {
            // Extract the content length header
            for (Header header : headers) {
                if (header.getName().equalsIgnoreCase(
                        HeaderConstants.HEADER_CONTENT_LENGTH)) {
                    try {
                        contentLength = Long.parseLong(header.getValue());
                    } catch (NumberFormatException e) {
                        contentLength = Representation.UNKNOWN_SIZE;
                    }
                }
            }
        }

        return contentLength;
    }

    /**
     * Indicates if the given character is alphabetical (a-z or A-Z).
     *
     * @param character
     *            The character to test.
     * @return True if the given character is alphabetical (a-z or A-Z).
     */
    public static boolean isAlpha(int character) {
        return isUpperCase(character) || isLowerCase(character);
    }

    /**
     * Indicates if the given character is in ASCII range.
     *
     * @param character
     *            The character to test.
     * @return True if the given character is in ASCII range.
     */
    public static boolean isAsciiChar(int character) {
        return (character >= 0) && (character <= 127);
    }

    /**
     * Indicates if the given character is a carriage return.
     *
     * @param character
     *            The character to test.
     * @return True if the given character is a carriage return.
     */
    public static boolean isCarriageReturn(int character) {
        return (character == 13);
    }

    /**
     * Indicates if the entity is chunked.
     *
     * @return True if the entity is chunked.
     */
    public static boolean isChunkedEncoding(Series<Header> headers) {
        boolean result = false;

        if (headers != null) {
            final String header = headers.getFirstValue(
                    HeaderConstants.HEADER_TRANSFER_ENCODING, true);
            result = "chunked".equalsIgnoreCase(header);
        }

        return result;
    }

    /**
     * Indicates if the given character is a comma, the character used as header
     * value separator.
     *
     * @param character
     *            The character to test.
     * @return True if the given character is a comma.
     */
    public static boolean isComma(int character) {
        return (character == ',');
    }

    /**
     * Indicates if the given character is a comment text. It means
     * {@link #isText(int)} returns true and the character is not '(' or ')'.
     *
     * @param character
     *            The character to test.
     * @return True if the given character is a quoted text.
     */
    public static boolean isCommentText(int character) {
        return isText(character) && (character != '(') && (character != ')');
    }

    /**
     * Indicates if the connection must be closed.
     *
     * @param headers
     *            The headers to test.
     * @return True if the connection must be closed.
     */
    public static boolean isConnectionClose(Series<Header> headers) {
        boolean result = false;

        if (headers != null) {
            String header = headers.getFirstValue(
                    HeaderConstants.HEADER_CONNECTION, true);
            result = "close".equalsIgnoreCase(header);
        }

        return result;
    }

    /**
     * Indicates if the given character is a control character.
     *
     * @param character
     *            The character to test.
     * @return True if the given character is a control character.
     */
    public static boolean isControlChar(int character) {
        return ((character >= 0) && (character <= 31)) || (character == 127);
    }

    /**
     * Indicates if the given character is a digit (0-9).
     *
     * @param character
     *            The character to test.
     * @return True if the given character is a digit (0-9).
     */
    public static boolean isDigit(int character) {
        return (character >= '0') && (character <= '9');
    }

    /**
     * Indicates if the given character is a double quote.
     *
     * @param character
     *            The character to test.
     * @return True if the given character is a double quote.
     */
    public static boolean isDoubleQuote(int character) {
        return (character == 34);
    }

    /**
     * Indicates if the given character is an horizontal tab.
     *
     * @param character
     *            The character to test.
     * @return True if the given character is an horizontal tab.
     */
    public static boolean isHorizontalTab(int character) {
        return (character == 9);
    }

    /**
     * Indicates if the given character is in ISO Latin 1 (8859-1) range. Note
     * that this range is a superset of ASCII and a subrange of Unicode (UTF-8).
     *
     * @param character
     *            The character to test.
     * @return True if the given character is in ISO Latin 1 range.
     */
    public static boolean isLatin1Char(int character) {
        return (character >= 0) && (character <= 255);
    }

    /**
     * Indicates if the given character is a value separator.
     *
     * @param character
     *            The character to test.
     * @return True if the given character is a value separator.
     */
    public static boolean isLinearWhiteSpace(int character) {
        return (isCarriageReturn(character) || isSpace(character)
                || isLineFeed(character) || HeaderUtils
                .isHorizontalTab(character));
    }

    /**
     * Indicates if the given character is a line feed.
     *
     * @param character
     *            The character to test.
     * @return True if the given character is a line feed.
     */
    public static boolean isLineFeed(int character) {
        return (character == 10);
    }

    /**
     * Indicates if the given character is lower case (a-z).
     *
     * @param character
     *            The character to test.
     * @return True if the given character is lower case (a-z).
     */
    public static boolean isLowerCase(int character) {
        return (character >= 'a') && (character <= 'z');
    }

    /**
     * Indicates if the given character marks the start of a quoted pair.
     *
     * @param character
     *            The character to test.
     * @return True if the given character marks the start of a quoted pair.
     */
    public static boolean isQuoteCharacter(int character) {
        return (character == '\\');
    }

    /**
     * Indicates if the given character is a quoted text. It means
     * {@link #isText(int)} returns true and {@link #isDoubleQuote(int)} returns
     * false.
     *
     * @param character
     *            The character to test.
     * @return True if the given character is a quoted text.
     */
    public static boolean isQuotedText(int character) {
        return isText(character) && !isDoubleQuote(character);
    }

    /**
     * Indicates if the given character is a semicolon, the character used as
     * header parameter separator.
     *
     * @param character
     *            The character to test.
     * @return True if the given character is a semicolon.
     */
    public static boolean isSemiColon(int character) {
        return (character == ';');
    }

    /**
     * Indicates if the given character is a separator.
     *
     * @param character
     *            The character to test.
     * @return True if the given character is a separator.
     */
    public static boolean isSeparator(int character) {
        switch (character) {
        case '(':
        case ')':
        case '<':
        case '>':
        case '@':
        case ',':
        case ';':
        case ':':
        case '\\':
        case '"':
        case '/':
        case '[':
        case ']':
        case '?':
        case '=':
        case '{':
        case '}':
        case ' ':
        case '\t':
            return true;

        default:
            return false;
        }
    }

    /**
     * Indicates if the given character is a space.
     *
     * @param character
     *            The character to test.
     * @return True if the given character is a space.
     */
    public static boolean isSpace(int character) {
        return (character == 32);
    }

    /**
     * Indicates if the given character is textual (ISO Latin 1 and not a
     * control character).
     *
     * @param character
     *            The character to test.
     * @return True if the given character is textual.
     */
    public static boolean isText(int character) {
        return isLatin1Char(character) && !isControlChar(character);
    }

    /**
     * Indicates if the token is valid.<br>
     * Only contains valid token characters.
     *
     * @param token
     *            The token to check
     * @return True if the token is valid.
     */
    public static boolean isToken(CharSequence token) {
        for (int i = 0; i < token.length(); i++) {
            if (!isTokenChar(token.charAt(i))) {
                return false;
            }
        }

        return true;
    }

    /**
     * Indicates if the given character is a token character (text and not a
     * separator).
     *
     * @param character
     *            The character to test.
     * @return True if the given character is a token character (text and not a
     *         separator).
     */
    public static boolean isTokenChar(int character) {
        return isAsciiChar(character) && !isSeparator(character);
    }

    /**
     * Indicates if the given character is upper case (A-Z).
     *
     * @param character
     *            The character to test.
     * @return True if the given character is upper case (A-Z).
     */
    public static boolean isUpperCase(int character) {
        return (character >= 'A') && (character <= 'Z');
    }



    /**
     * Private constructor to ensure that the class acts as a true utility class
     * i.e. it isn't instantiable and extensible.
     */
    private HeaderUtils() {
    }
}
TOP

Related Classes of org.restlet.client.engine.header.HeaderUtils

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.