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

io.undertow.protocols.http2.Hpack 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).

There is a newer version: 34.0.0.Final
Show 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.protocols.http2;

import java.nio.ByteBuffer;

import io.undertow.UndertowMessages;
import io.undertow.util.HttpString;

/**
 * @author Stuart Douglas
 */
final class Hpack {

    private static final byte LOWER_DIFF = 'a' - 'A';
    static final int DEFAULT_TABLE_SIZE = 4096;
    private static final int MAX_INTEGER_OCTETS = 8; //not sure what a good value for this is, but the spec says we need to provide an upper bound

    /**
     * table that contains powers of two,
     * used as both bitmask and to quickly calculate 2^n
     */
    private static final int[] PREFIX_TABLE;


    static final HeaderField[] STATIC_TABLE;
    static final int STATIC_TABLE_LENGTH;

    static {
        PREFIX_TABLE = new int[32];
        for (int i = 0; i < 32; ++i) {
            int n = 0;
            for (int j = 0; j < i; ++j) {
                n = n << 1;
                n |= 1;
            }
            PREFIX_TABLE[i] = n;
        }

        HeaderField[] fields = new HeaderField[62];
        //note that zero is not used
        fields[1] = new HeaderField(new HttpString(":authority"), null);
        fields[2] = new HeaderField(new HttpString(":method"), "GET");
        fields[3] = new HeaderField(new HttpString(":method"), "POST");
        fields[4] = new HeaderField(new HttpString(":path"), "/");
        fields[5] = new HeaderField(new HttpString(":path"), "/index.html");
        fields[6] = new HeaderField(new HttpString(":scheme"), "http");
        fields[7] = new HeaderField(new HttpString(":scheme"), "https");
        fields[8] = new HeaderField(new HttpString(":status"), "200");
        fields[9] = new HeaderField(new HttpString(":status"), "204");
        fields[10] = new HeaderField(new HttpString(":status"), "206");
        fields[11] = new HeaderField(new HttpString(":status"), "304");
        fields[12] = new HeaderField(new HttpString(":status"), "400");
        fields[13] = new HeaderField(new HttpString(":status"), "404");
        fields[14] = new HeaderField(new HttpString(":status"), "500");
        fields[15] = new HeaderField(new HttpString("accept-charset"), null);
        fields[16] = new HeaderField(new HttpString("accept-encoding"), "gzip, deflate");
        fields[17] = new HeaderField(new HttpString("accept-language"), null);
        fields[18] = new HeaderField(new HttpString("accept-ranges"), null);
        fields[19] = new HeaderField(new HttpString("accept"), null);
        fields[20] = new HeaderField(new HttpString("access-control-allow-origin"), null);
        fields[21] = new HeaderField(new HttpString("age"), null);
        fields[22] = new HeaderField(new HttpString("allow"), null);
        fields[23] = new HeaderField(new HttpString("authorization"), null);
        fields[24] = new HeaderField(new HttpString("cache-control"), null);
        fields[25] = new HeaderField(new HttpString("content-disposition"), null);
        fields[26] = new HeaderField(new HttpString("content-encoding"), null);
        fields[27] = new HeaderField(new HttpString("content-language"), null);
        fields[28] = new HeaderField(new HttpString("content-length"), null);
        fields[29] = new HeaderField(new HttpString("content-location"), null);
        fields[30] = new HeaderField(new HttpString("content-range"), null);
        fields[31] = new HeaderField(new HttpString("content-type"), null);
        fields[32] = new HeaderField(new HttpString("cookie"), null);
        fields[33] = new HeaderField(new HttpString("date"), null);
        fields[34] = new HeaderField(new HttpString("etag"), null);
        fields[35] = new HeaderField(new HttpString("expect"), null);
        fields[36] = new HeaderField(new HttpString("expires"), null);
        fields[37] = new HeaderField(new HttpString("from"), null);
        fields[38] = new HeaderField(new HttpString("host"), null);
        fields[39] = new HeaderField(new HttpString("if-match"), null);
        fields[40] = new HeaderField(new HttpString("if-modified-since"), null);
        fields[41] = new HeaderField(new HttpString("if-none-match"), null);
        fields[42] = new HeaderField(new HttpString("if-range"), null);
        fields[43] = new HeaderField(new HttpString("if-unmodified-since"), null);
        fields[44] = new HeaderField(new HttpString("last-modified"), null);
        fields[45] = new HeaderField(new HttpString("link"), null);
        fields[46] = new HeaderField(new HttpString("location"), null);
        fields[47] = new HeaderField(new HttpString("max-forwards"), null);
        fields[48] = new HeaderField(new HttpString("proxy-authenticate"), null);
        fields[49] = new HeaderField(new HttpString("proxy-authorization"), null);
        fields[50] = new HeaderField(new HttpString("range"), null);
        fields[51] = new HeaderField(new HttpString("referer"), null);
        fields[52] = new HeaderField(new HttpString("refresh"), null);
        fields[53] = new HeaderField(new HttpString("retry-after"), null);
        fields[54] = new HeaderField(new HttpString("server"), null);
        fields[55] = new HeaderField(new HttpString("set-cookie"), null);
        fields[56] = new HeaderField(new HttpString("strict-transport-security"), null);
        fields[57] = new HeaderField(new HttpString("transfer-encoding"), null);
        fields[58] = new HeaderField(new HttpString("user-agent"), null);
        fields[59] = new HeaderField(new HttpString("vary"), null);
        fields[60] = new HeaderField(new HttpString("via"), null);
        fields[61] = new HeaderField(new HttpString("www-authenticate"), null);
        STATIC_TABLE = fields;
        STATIC_TABLE_LENGTH = STATIC_TABLE.length - 1;
    }

    static class HeaderField {
        final HttpString name;
        final String value;
        final int size;

        HeaderField(HttpString name, String value) {
            this.name = name;
            this.value = value;
            if (value != null) {
                this.size = 32 + name.length() + value.length();
            } else {
                this.size = -1;
            }
        }
    }

    /**
     * Decodes an integer in the HPACK prefex format. If the return value is -1
     * it means that there was not enough data in the buffer to complete the decoding
     * sequence.
     * 

* If this method returns -1 then the source buffer will not have been modified. * * @param source The buffer that contains the integer * @param n The encoding prefix length * @return The encoded integer, or -1 if there was not enough data */ static int decodeInteger(ByteBuffer source, int n) throws HpackException { if (source.remaining() == 0) { return -1; } if(n >= PREFIX_TABLE.length) { throw UndertowMessages.MESSAGES.integerEncodedOverTooManyOctets(MAX_INTEGER_OCTETS); } int count = 1; int sp = source.position(); int mask = PREFIX_TABLE[n]; int i = mask & source.get(); int b; if (i < PREFIX_TABLE[n]) { return i; } else { int m = 0; do { if(count++ > MAX_INTEGER_OCTETS) { throw UndertowMessages.MESSAGES.integerEncodedOverTooManyOctets(MAX_INTEGER_OCTETS); } if (source.remaining() == 0) { //we have run out of data //reset source.position(sp); return -1; } if(m >= PREFIX_TABLE.length) { throw UndertowMessages.MESSAGES.integerEncodedOverTooManyOctets(MAX_INTEGER_OCTETS); } b = source.get(); i = i + (b & 127) * (PREFIX_TABLE[m] + 1); m += 7; } while ((b & 128) == 128); } return i; } /** * Encodes an integer in the HPACK prefix format. *

* This method assumes that the buffer has already had the first 8-n bits filled. * As such it will modify the last byte that is already present in the buffer, and * potentially add more if required * * @param source The buffer that contains the integer * @param value The integer to encode * @param n The encoding prefix length */ static void encodeInteger(ByteBuffer source, int value, int n) { int twoNminus1 = PREFIX_TABLE[n]; int pos = source.position() - 1; if (value < twoNminus1) { source.put(pos, (byte) (source.get(pos) | value)); } else { source.put(pos, (byte) (source.get(pos) | twoNminus1)); value = value - twoNminus1; while (value >= 128) { source.put((byte) (value % 128 + 128)); value = value / 128; } source.put((byte) value); } } static byte toLower(byte b) { if (b >= 'A' && b <= 'Z') { return (byte) (b + LOWER_DIFF); } return b; } private Hpack() {} }





© 2015 - 2024 Weber Informatics LLC | Privacy Policy