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

de.mklinger.qetcher.client.jetty.http2.parser.Parser Maven / Gradle / Ivy

There is a newer version: 2.0.42.rc
Show newest version
//
//  ========================================================================
//  Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd.
//  ------------------------------------------------------------------------
//  All rights reserved. This program and the accompanying materials
//  are made available under the terms of the Eclipse Public License v1.0
//  and Apache License v2.0 which accompanies this distribution.
//
//      The Eclipse Public License is available at
//      http://www.eclipse.org/legal/epl-v10.html
//
//      The Apache License v2.0 is available at
//      http://www.opensource.org/licenses/apache2.0.php
//
//  You may elect to redistribute this code under either of these licenses.
//  ========================================================================
//

package org.eclipse.jetty.http2.parser;

import java.nio.ByteBuffer;
import java.util.function.UnaryOperator;

import org.eclipse.jetty.http2.ErrorCode;
import org.eclipse.jetty.http2.Flags;
import org.eclipse.jetty.http2.frames.DataFrame;
import org.eclipse.jetty.http2.frames.FrameType;
import org.eclipse.jetty.http2.frames.GoAwayFrame;
import org.eclipse.jetty.http2.frames.HeadersFrame;
import org.eclipse.jetty.http2.frames.PingFrame;
import org.eclipse.jetty.http2.frames.PriorityFrame;
import org.eclipse.jetty.http2.frames.PushPromiseFrame;
import org.eclipse.jetty.http2.frames.ResetFrame;
import org.eclipse.jetty.http2.frames.SettingsFrame;
import org.eclipse.jetty.http2.frames.WindowUpdateFrame;
import org.eclipse.jetty.http2.hpack.HpackDecoder;
import org.eclipse.jetty.io.ByteBufferPool;
import org.eclipse.jetty.util.BufferUtil;
import org.eclipse.jetty.util.log.Log;
import org.eclipse.jetty.util.log.Logger;

/**
 * 

The HTTP/2 protocol parser.

*

This parser makes use of the {@link HeaderParser} and of * {@link BodyParser}s to parse HTTP/2 frames.

*/ public class Parser { private static final Logger LOG = Log.getLogger(Parser.class); private final Listener listener; private final HeaderParser headerParser; private final HeaderBlockParser headerBlockParser; private final BodyParser[] bodyParsers; private boolean continuation; private State state = State.HEADER; public Parser(ByteBufferPool byteBufferPool, Listener listener, int maxDynamicTableSize, int maxHeaderSize) { this.listener = listener; this.headerParser = new HeaderParser(); this.headerBlockParser = new HeaderBlockParser(byteBufferPool, new HpackDecoder(maxDynamicTableSize, maxHeaderSize)); this.bodyParsers = new BodyParser[FrameType.values().length]; } public void init(UnaryOperator wrapper) { Listener listener = wrapper.apply(this.listener); HeaderBlockFragments headerBlockFragments = new HeaderBlockFragments(); bodyParsers[FrameType.DATA.getType()] = new DataBodyParser(headerParser, listener); bodyParsers[FrameType.HEADERS.getType()] = new HeadersBodyParser(headerParser, listener, headerBlockParser, headerBlockFragments); bodyParsers[FrameType.PRIORITY.getType()] = new PriorityBodyParser(headerParser, listener); bodyParsers[FrameType.RST_STREAM.getType()] = new ResetBodyParser(headerParser, listener); bodyParsers[FrameType.SETTINGS.getType()] = new SettingsBodyParser(headerParser, listener); bodyParsers[FrameType.PUSH_PROMISE.getType()] = new PushPromiseBodyParser(headerParser, listener, headerBlockParser); bodyParsers[FrameType.PING.getType()] = new PingBodyParser(headerParser, listener); bodyParsers[FrameType.GO_AWAY.getType()] = new GoAwayBodyParser(headerParser, listener); bodyParsers[FrameType.WINDOW_UPDATE.getType()] = new WindowUpdateBodyParser(headerParser, listener); bodyParsers[FrameType.CONTINUATION.getType()] = new ContinuationBodyParser(headerParser, listener, headerBlockParser, headerBlockFragments); } private void reset() { headerParser.reset(); state = State.HEADER; } /** *

Parses the given {@code buffer} bytes and emit events to a {@link Listener}.

*

When this method returns, the buffer may not be fully consumed, so invocations * to this method should be wrapped in a loop:

*
     * while (buffer.hasRemaining())
     *     parser.parse(buffer);
     * 
* * @param buffer the buffer to parse */ public void parse(ByteBuffer buffer) { try { while (true) { switch (state) { case HEADER: { if (!parseHeader(buffer)) return; break; } case BODY: { if (!parseBody(buffer)) return; break; } default: { throw new IllegalStateException(); } } } } catch (Throwable x) { if (LOG.isDebugEnabled()) LOG.debug(x); BufferUtil.clear(buffer); notifyConnectionFailure(ErrorCode.PROTOCOL_ERROR.code, "parser_error"); } } protected boolean parseHeader(ByteBuffer buffer) { if (!headerParser.parse(buffer)) return false; FrameType frameType = FrameType.from(getFrameType()); if (LOG.isDebugEnabled()) LOG.debug("Parsed {} frame header from {}", frameType, buffer); if (continuation) { if (frameType != FrameType.CONTINUATION) { // SPEC: CONTINUATION frames must be consecutive. BufferUtil.clear(buffer); notifyConnectionFailure(ErrorCode.PROTOCOL_ERROR.code, "continuation_frame_expected"); return false; } if (headerParser.hasFlag(Flags.END_HEADERS)) { continuation = false; } } else { if (frameType == FrameType.HEADERS && !headerParser.hasFlag(Flags.END_HEADERS)) { continuation = true; } } state = State.BODY; return true; } protected boolean parseBody(ByteBuffer buffer) { int type = getFrameType(); if (type < 0 || type >= bodyParsers.length) { BufferUtil.clear(buffer); notifyConnectionFailure(ErrorCode.PROTOCOL_ERROR.code, "unknown_frame_type_" + type); return false; } BodyParser bodyParser = bodyParsers[type]; if (headerParser.getLength() == 0) { bodyParser.emptyBody(buffer); } else { if (!bodyParser.parse(buffer)) return false; } if (LOG.isDebugEnabled()) LOG.debug("Parsed {} frame body from {}", FrameType.from(type), buffer); reset(); return true; } protected int getFrameType() { return headerParser.getFrameType(); } protected boolean hasFlag(int bit) { return headerParser.hasFlag(bit); } protected void notifyConnectionFailure(int error, String reason) { try { listener.onConnectionFailure(error, reason); } catch (Throwable x) { LOG.info("Failure while notifying listener " + listener, x); } } public interface Listener { public void onData(DataFrame frame); public void onHeaders(HeadersFrame frame); public void onPriority(PriorityFrame frame); public void onReset(ResetFrame frame); public void onSettings(SettingsFrame frame); public void onPushPromise(PushPromiseFrame frame); public void onPing(PingFrame frame); public void onGoAway(GoAwayFrame frame); public void onWindowUpdate(WindowUpdateFrame frame); public void onConnectionFailure(int error, String reason); public static class Adapter implements Listener { @Override public void onData(DataFrame frame) { } @Override public void onHeaders(HeadersFrame frame) { } @Override public void onPriority(PriorityFrame frame) { } @Override public void onReset(ResetFrame frame) { } @Override public void onSettings(SettingsFrame frame) { } @Override public void onPushPromise(PushPromiseFrame frame) { } @Override public void onPing(PingFrame frame) { } @Override public void onGoAway(GoAwayFrame frame) { } @Override public void onWindowUpdate(WindowUpdateFrame frame) { } @Override public void onConnectionFailure(int error, String reason) { LOG.warn("Connection failure: {}/{}", error, reason); } } } private enum State { HEADER, BODY } }




© 2015 - 2024 Weber Informatics LLC | Privacy Policy