All Downloads are FREE. Search and download functionalities are using the official Maven repository.

io.undertow.util.QValueParser Maven / Gradle / Ivy

Go to download

This artifact provides a single jar that contains all classes required to use remote EJB and JMS, including all dependencies. It is intended for use by those not using maven, maven users should just import the EJB and JMS BOM's instead (shaded JAR's cause lots of problems with maven, as it is very easy to inadvertently end up with different versions on classes on the class path).

The newest version!
/*
 * JBoss, Home of Professional Open Source.
 * Copyright 2014 Red Hat, Inc., and individual contributors
 * as indicated by the @author tags.
 *
 * Licensed 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.
 */

package io.undertow.util;

import java.util.ArrayList;
import java.util.Collections;
import java.util.List;

/**
 * Utility class for parsing headers that accept q values
 *
 * @author Stuart Douglas
 */
public class QValueParser {

    private QValueParser() {

    }

    /**
     * Parses a set of headers that take q values to determine the most preferred one.
     *
     * It returns the result in the form of a sorted list of list, with every element in
     * the list having the same q value. This means the highest priority items are at the
     * front of the list. The container should use its own internal preferred ordering
     * to determinately pick the correct item to use
     *
     * @param headers The headers
     * @return The q value results
     */
    public static List> parse(List headers) {
        final List found = new ArrayList<>();
        QValueResult current = null;
        //noinspection ForLoopReplaceableByForEach - using induction for loop for iteration to avoid allocation
        for (int j = 0; j < headers.size(); j++) {
            final String header = headers.get(j);
            final int l = header.length();
            //we do not use a string builder
            //we just keep track of where the current string starts and call substring()
            int stringStart = 0;
            for (int i = 0; i < l; ++i) {
                char c = header.charAt(i);
                switch (c) {
                    case ',': {
                        if (current != null &&
                                (i - stringStart > 2 && header.charAt(stringStart) == 'q' &&
                                        header.charAt(stringStart + 1) == '=')) {
                            //if this is a valid qvalue
                            current.qvalue = header.substring(stringStart + 2, i);
                            current = null;
                        } else if (stringStart != i) {
                            current = handleNewEncoding(found, header, stringStart, i);
                        }
                        stringStart = i + 1;
                        break;
                    }
                    case ';': {
                        if (stringStart != i) {
                            current = handleNewEncoding(found, header, stringStart, i);
                            stringStart = i + 1;
                        }
                        break;
                    }
                    case ' ': {
                        if (stringStart != i) {
                            if (current != null &&
                                    (i - stringStart > 2 && header.charAt(stringStart) == 'q' &&
                                            header.charAt(stringStart + 1) == '=')) {
                                //if this is a valid qvalue
                                current.qvalue = header.substring(stringStart + 2, i);
                            } else {
                                current = handleNewEncoding(found, header, stringStart, i);
                            }
                        }
                        stringStart = i + 1;
                    }
                }
            }

            if (stringStart != l) {
                if (current != null &&
                        (l - stringStart > 2 && header.charAt(stringStart) == 'q' &&
                                header.charAt(stringStart + 1) == '=')) {
                    //if this is a valid qvalue
                    current.qvalue = header.substring(stringStart + 2, l);
                } else {
                    current = handleNewEncoding(found, header, stringStart, l);
                }
            }
        }
        Collections.sort(found, Collections.reverseOrder());
        String currentQValue = null;
        List> values = new ArrayList<>();
        List currentSet = null;

        //noinspection ForLoopReplaceableByForEach - using induction for loop for iteration to avoid allocation
        for (int i = 0; i < found.size(); i++) {
            final QValueResult val = found.get(i);
            if (!val.qvalue.equals(currentQValue)) {
                currentQValue = val.qvalue;
                currentSet = new ArrayList<>();
                values.add(currentSet);
            }
            currentSet.add(val);
        }
        return values;
    }

    private static QValueResult handleNewEncoding(final List found, final String header, final int stringStart, final int i) {
        final QValueResult current = new QValueResult();
        current.value = header.substring(stringStart, i);
        found.add(current);
        return current;
    }

    public static class QValueResult implements Comparable {


        /**
         * The string value of the result
         */
        private String value;

        /**
         * we keep the qvalue as a string to avoid parsing the double.
         * 

* This should give both performance and also possible security improvements */ private String qvalue = "1"; public String getValue() { return value; } public String getQvalue() { return qvalue; } @Override public boolean equals(Object o) { if (this == o) return true; if (!(o instanceof QValueResult)) return false; QValueResult that = (QValueResult) o; if (getValue() != null ? !getValue().equals(that.getValue()) : that.getValue() != null) return false; return getQvalue() != null ? getQvalue().equals(that.getQvalue()) : that.getQvalue() == null; } @Override public int hashCode() { int result = getValue() != null ? getValue().hashCode() : 0; result = 31 * result + (getQvalue() != null ? getQvalue().hashCode() : 0); return result; } @Override public int compareTo(final QValueResult other) { //we compare the strings as if they were decimal values. //we know they can only be final String t = qvalue; final String o = other.qvalue; if (t == null && o == null) { //neither of them has a q value //we compare them via the server specified default precedence //note that encoding is never null here, a * without a q value is meaningless //and will be discarded before this return 0; } if (o == null) { return 1; } else if (t == null) { return -1; } final int tl = t.length(); final int ol = o.length(); //we only compare the first 5 characters as per spec for (int i = 0; i < 5; ++i) { if (tl == i || ol == i) { return ol - tl; //longer one is higher } if (i == 1) continue; // this is just the decimal point final int tc = t.charAt(i); final int oc = o.charAt(i); int res = tc - oc; if (res != 0) { return res; } } return 0; } public boolean isQValueZero() { //we ignore * without a qvalue if (qvalue != null) { int length = Math.min(5, qvalue.length()); //we need to find out if this is prohibiting identity //encoding (q=0). Otherwise we just treat it as the identity encoding boolean zero = true; for (int j = 0; j < length; ++j) { if (j == 1) continue;//decimal point if (qvalue.charAt(j) != '0') { zero = false; break; } } return zero; } return false; } } }





© 2015 - 2024 Weber Informatics LLC | Privacy Policy