Search in sources :

Example 6 with HttpHeader

use of org.eclipse.jetty.http.HttpHeader in project jetty.project by eclipse.

the class HpackDecoder method decode.

public MetaData decode(ByteBuffer buffer) {
    if (LOG.isDebugEnabled())
        LOG.debug(String.format("CtxTbl[%x] decoding %d octets", _context.hashCode(), buffer.remaining()));
    // If the buffer is big, don't even think about decoding it
    if (buffer.remaining() > _builder.getMaxSize())
        throw new BadMessageException(HttpStatus.REQUEST_HEADER_FIELDS_TOO_LARGE_431, "Header frame size " + buffer.remaining() + ">" + _builder.getMaxSize());
    while (buffer.hasRemaining()) {
        if (LOG.isDebugEnabled() && buffer.hasArray()) {
            int l = Math.min(buffer.remaining(), 32);
            LOG.debug("decode {}{}", TypeUtil.toHexString(buffer.array(), buffer.arrayOffset() + buffer.position(), l), l < buffer.remaining() ? "..." : "");
        }
        byte b = buffer.get();
        if (b < 0) {
            // 7.1 indexed if the high bit is set
            int index = NBitInteger.decode(buffer, 7);
            Entry entry = _context.get(index);
            if (entry == null) {
                throw new BadMessageException(HttpStatus.BAD_REQUEST_400, "Unknown index " + index);
            } else if (entry.isStatic()) {
                if (LOG.isDebugEnabled())
                    LOG.debug("decode IdxStatic {}", entry);
                // emit field
                _builder.emit(entry.getHttpField());
            // TODO copy and add to reference set if there is room
            // _context.add(entry.getHttpField());
            } else {
                if (LOG.isDebugEnabled())
                    LOG.debug("decode Idx {}", entry);
                // emit
                _builder.emit(entry.getHttpField());
            }
        } else {
            // look at the first nibble in detail
            byte f = (byte) ((b & 0xF0) >> 4);
            String name;
            HttpHeader header;
            String value;
            boolean indexed;
            int name_index;
            switch(f) {
                // 7.3
                case 2:
                case // 7.3
                3:
                    // change table size
                    int size = NBitInteger.decode(buffer, 5);
                    if (LOG.isDebugEnabled())
                        LOG.debug("decode resize=" + size);
                    if (size > _localMaxDynamicTableSize)
                        throw new IllegalArgumentException();
                    _context.resize(size);
                    continue;
                // 7.2.2
                case 0:
                case // 7.2.3
                1:
                    indexed = false;
                    name_index = NBitInteger.decode(buffer, 4);
                    break;
                // 7.2.1
                case 4:
                // 7.2.1
                case 5:
                // 7.2.1
                case 6:
                case // 7.2.1
                7:
                    indexed = true;
                    name_index = NBitInteger.decode(buffer, 6);
                    break;
                default:
                    throw new IllegalStateException();
            }
            boolean huffmanName = false;
            // decode the name
            if (name_index > 0) {
                Entry name_entry = _context.get(name_index);
                name = name_entry.getHttpField().getName();
                header = name_entry.getHttpField().getHeader();
            } else {
                huffmanName = (buffer.get() & 0x80) == 0x80;
                int length = NBitInteger.decode(buffer, 7);
                _builder.checkSize(length, huffmanName);
                if (huffmanName)
                    name = Huffman.decode(buffer, length);
                else
                    name = toASCIIString(buffer, length);
                for (int i = 0; i < name.length(); i++) {
                    char c = name.charAt(i);
                    if (c >= 'A' && c <= 'Z') {
                        throw new BadMessageException(400, "Uppercase header name");
                    }
                }
                header = HttpHeader.CACHE.get(name);
            }
            // decode the value
            boolean huffmanValue = (buffer.get() & 0x80) == 0x80;
            int length = NBitInteger.decode(buffer, 7);
            _builder.checkSize(length, huffmanValue);
            if (huffmanValue)
                value = Huffman.decode(buffer, length);
            else
                value = toASCIIString(buffer, length);
            // Make the new field
            HttpField field;
            if (header == null) {
                // just make a normal field and bypass header name lookup
                field = new HttpField(null, name, value);
            } else {
                // and/or of a type that may be looked up multiple times.
                switch(header) {
                    case C_STATUS:
                        if (indexed)
                            field = new HttpField.IntValueHttpField(header, name, value);
                        else
                            field = new HttpField(header, name, value);
                        break;
                    case C_AUTHORITY:
                        field = new AuthorityHttpField(value);
                        break;
                    case CONTENT_LENGTH:
                        if ("0".equals(value))
                            field = CONTENT_LENGTH_0;
                        else
                            field = new HttpField.LongValueHttpField(header, name, value);
                        break;
                    default:
                        field = new HttpField(header, name, value);
                        break;
                }
            }
            if (LOG.isDebugEnabled()) {
                LOG.debug("decoded '{}' by {}/{}/{}", field, name_index > 0 ? "IdxName" : (huffmanName ? "HuffName" : "LitName"), huffmanValue ? "HuffVal" : "LitVal", indexed ? "Idx" : "");
            }
            // emit the field
            _builder.emit(field);
            // if indexed
            if (indexed) {
                // add to dynamic table
                if (_context.add(field) == null)
                    throw new BadMessageException(HttpStatus.REQUEST_HEADER_FIELDS_TOO_LARGE_431, "Indexed field value too large");
            }
        }
    }
    return _builder.build();
}
Also used : BadMessageException(org.eclipse.jetty.http.BadMessageException) Entry(org.eclipse.jetty.http2.hpack.HpackContext.Entry) HttpHeader(org.eclipse.jetty.http.HttpHeader) HttpField(org.eclipse.jetty.http.HttpField)

Example 7 with HttpHeader

use of org.eclipse.jetty.http.HttpHeader in project jetty.project by eclipse.

the class HpackEncoder method encode.

public void encode(ByteBuffer buffer, HttpField field) {
    if (field.getValue() == null)
        field = new HttpField(field.getHeader(), field.getName(), "");
    int field_size = field.getName().length() + field.getValue().length();
    _headerListSize += field_size + 32;
    final int p = _debug ? buffer.position() : -1;
    String encoding = null;
    // Is there an entry for the field?
    Entry entry = _context.get(field);
    if (entry != null) {
        // Known field entry, so encode it as indexed
        if (entry.isStatic()) {
            buffer.put(((StaticEntry) entry).getEncodedField());
            if (_debug)
                encoding = "IdxFieldS1";
        } else {
            int index = _context.index(entry);
            buffer.put((byte) 0x80);
            NBitInteger.encode(buffer, 7, index);
            if (_debug)
                encoding = "IdxField" + (entry.isStatic() ? "S" : "") + (1 + NBitInteger.octectsNeeded(7, index));
        }
    } else {
        // Unknown field entry, so we will have to send literally.
        final boolean indexed;
        // But do we know it's name?
        HttpHeader header = field.getHeader();
        // Select encoding strategy
        if (header == null) {
            // Select encoding strategy for unknown header names
            Entry name = _context.get(field.getName());
            if (field instanceof PreEncodedHttpField) {
                int i = buffer.position();
                ((PreEncodedHttpField) field).putTo(buffer, HttpVersion.HTTP_2);
                byte b = buffer.get(i);
                indexed = b < 0 || b >= 0x40;
                if (_debug)
                    encoding = indexed ? "PreEncodedIdx" : "PreEncoded";
            } else // has the custom header name been seen before?
            if (name == null) {
                // unknown name and value, so let's index this just in case it is
                // the first time we have seen a custom name or a custom field.
                // unless the name is changing, this is worthwhile
                indexed = true;
                encodeName(buffer, (byte) 0x40, 6, field.getName(), null);
                encodeValue(buffer, true, field.getValue());
                if (_debug)
                    encoding = "LitHuffNHuffVIdx";
            } else {
                // known custom name, but unknown value.
                // This is probably a custom field with changing value, so don't index.
                indexed = false;
                encodeName(buffer, (byte) 0x00, 4, field.getName(), null);
                encodeValue(buffer, true, field.getValue());
                if (_debug)
                    encoding = "LitHuffNHuffV!Idx";
            }
        } else {
            // Select encoding strategy for known header names
            Entry name = _context.get(header);
            if (field instanceof PreEncodedHttpField) {
                // Preencoded field
                int i = buffer.position();
                ((PreEncodedHttpField) field).putTo(buffer, HttpVersion.HTTP_2);
                byte b = buffer.get(i);
                indexed = b < 0 || b >= 0x40;
                if (_debug)
                    encoding = indexed ? "PreEncodedIdx" : "PreEncoded";
            } else if (__DO_NOT_INDEX.contains(header)) {
                // Non indexed field
                indexed = false;
                boolean never_index = __NEVER_INDEX.contains(header);
                boolean huffman = !__DO_NOT_HUFFMAN.contains(header);
                encodeName(buffer, never_index ? (byte) 0x10 : (byte) 0x00, 4, header.asString(), name);
                encodeValue(buffer, huffman, field.getValue());
                if (_debug)
                    encoding = "Lit" + ((name == null) ? "HuffN" : ("IdxN" + (name.isStatic() ? "S" : "") + (1 + NBitInteger.octectsNeeded(4, _context.index(name))))) + (huffman ? "HuffV" : "LitV") + (indexed ? "Idx" : (never_index ? "!!Idx" : "!Idx"));
            } else if (field_size >= _context.getMaxDynamicTableSize() || header == HttpHeader.CONTENT_LENGTH && field.getValue().length() > 2) {
                // Non indexed if field too large or a content length for 3 digits or more
                indexed = false;
                encodeName(buffer, (byte) 0x00, 4, header.asString(), name);
                encodeValue(buffer, true, field.getValue());
                if (_debug)
                    encoding = "LitIdxNS" + (1 + NBitInteger.octectsNeeded(4, _context.index(name))) + "HuffV!Idx";
            } else {
                // indexed
                indexed = true;
                boolean huffman = !__DO_NOT_HUFFMAN.contains(header);
                encodeName(buffer, (byte) 0x40, 6, header.asString(), name);
                encodeValue(buffer, huffman, field.getValue());
                if (_debug)
                    encoding = ((name == null) ? "LitHuffN" : ("LitIdxN" + (name.isStatic() ? "S" : "") + (1 + NBitInteger.octectsNeeded(6, _context.index(name))))) + (huffman ? "HuffVIdx" : "LitVIdx");
            }
        }
        // table and reference set.
        if (indexed)
            if (_context.add(field) == null)
                throw new IllegalStateException();
    }
    if (_debug) {
        int e = buffer.position();
        if (LOG.isDebugEnabled())
            LOG.debug("encode {}:'{}' to '{}'", encoding, field, TypeUtil.toHexString(buffer.array(), buffer.arrayOffset() + p, e - p));
    }
}
Also used : StaticEntry(org.eclipse.jetty.http2.hpack.HpackContext.StaticEntry) Entry(org.eclipse.jetty.http2.hpack.HpackContext.Entry) HttpHeader(org.eclipse.jetty.http.HttpHeader) HttpField(org.eclipse.jetty.http.HttpField) PreEncodedHttpField(org.eclipse.jetty.http.PreEncodedHttpField) PreEncodedHttpField(org.eclipse.jetty.http.PreEncodedHttpField)

Example 8 with HttpHeader

use of org.eclipse.jetty.http.HttpHeader in project jetty.project by eclipse.

the class MetaDataBuilder method emit.

public void emit(HttpField field) {
    HttpHeader header = field.getHeader();
    String name = field.getName();
    String value = field.getValue();
    int field_size = name.length() + (value == null ? 0 : value.length());
    _size += field_size + 32;
    if (_size > _maxSize)
        throw new BadMessageException(HttpStatus.REQUEST_HEADER_FIELDS_TOO_LARGE_431, "Header size " + _size + ">" + _maxSize);
    if (field instanceof StaticTableHttpField) {
        StaticTableHttpField staticField = (StaticTableHttpField) field;
        switch(header) {
            case C_STATUS:
                _status = (Integer) staticField.getStaticValue();
                break;
            case C_METHOD:
                _method = value;
                break;
            case C_SCHEME:
                _scheme = (HttpScheme) staticField.getStaticValue();
                break;
            default:
                throw new IllegalArgumentException(name);
        }
    } else if (header != null) {
        switch(header) {
            case C_STATUS:
                _status = field.getIntValue();
                break;
            case C_METHOD:
                _method = value;
                break;
            case C_SCHEME:
                if (value != null)
                    _scheme = HttpScheme.CACHE.get(value);
                break;
            case C_AUTHORITY:
                if (field instanceof HostPortHttpField)
                    _authority = (HostPortHttpField) field;
                else if (value != null)
                    _authority = new AuthorityHttpField(value);
                break;
            case HOST:
                // :authority fields must come first.  If we have one, ignore the host header as far as authority goes.
                if (_authority == null) {
                    if (field instanceof HostPortHttpField)
                        _authority = (HostPortHttpField) field;
                    else if (value != null)
                        _authority = new AuthorityHttpField(value);
                }
                _fields.add(field);
                break;
            case C_PATH:
                _path = value;
                break;
            case CONTENT_LENGTH:
                _contentLength = field.getLongValue();
                _fields.add(field);
                break;
            default:
                if (name.charAt(0) != ':')
                    _fields.add(field);
                break;
        }
    } else {
        if (name.charAt(0) != ':')
            _fields.add(field);
    }
}
Also used : HttpHeader(org.eclipse.jetty.http.HttpHeader) BadMessageException(org.eclipse.jetty.http.BadMessageException) HostPortHttpField(org.eclipse.jetty.http.HostPortHttpField)

Aggregations

HttpHeader (org.eclipse.jetty.http.HttpHeader)8 HttpField (org.eclipse.jetty.http.HttpField)5 HostPortHttpField (org.eclipse.jetty.http.HostPortHttpField)3 BadMessageException (org.eclipse.jetty.http.BadMessageException)2 HttpFields (org.eclipse.jetty.http.HttpFields)2 Entry (org.eclipse.jetty.http2.hpack.HpackContext.Entry)2 URI (java.net.URI)1 ArrayDeque (java.util.ArrayDeque)1 ServletRequest (javax.servlet.ServletRequest)1 HttpServletRequest (javax.servlet.http.HttpServletRequest)1 HttpSession (javax.servlet.http.HttpSession)1 Request (org.eclipse.jetty.client.api.Request)1 HttpHeaderValue (org.eclipse.jetty.http.HttpHeaderValue)1 HttpURI (org.eclipse.jetty.http.HttpURI)1 PreEncodedHttpField (org.eclipse.jetty.http.PreEncodedHttpField)1 StaticEntry (org.eclipse.jetty.http2.hpack.HpackContext.StaticEntry)1 PushBuilder (org.eclipse.jetty.server.PushBuilder)1 Request (org.eclipse.jetty.server.Request)1