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

com.firefly.codec.http2.decode.GoAwayBodyParser Maven / Gradle / Ivy

There is a newer version: 4.0.3.2
Show newest version
package com.firefly.codec.http2.decode;

import java.nio.ByteBuffer;

import com.firefly.codec.http2.frame.ErrorCode;
import com.firefly.codec.http2.frame.GoAwayFrame;

public class GoAwayBodyParser extends BodyParser {
	private State state = State.PREPARE;
	private int cursor;
	private int length;
	private int lastStreamId;
	private int error;
	private byte[] payload;

	public GoAwayBodyParser(HeaderParser headerParser, Parser.Listener listener) {
		super(headerParser, listener);
	}

	private void reset() {
		state = State.PREPARE;
		cursor = 0;
		length = 0;
		lastStreamId = 0;
		error = 0;
		payload = null;
	}

	@Override
	public boolean parse(ByteBuffer buffer) {
		while (buffer.hasRemaining()) {
			switch (state) {
			case PREPARE: {
				state = State.LAST_STREAM_ID;
				length = getBodyLength();
				break;
			}
			case LAST_STREAM_ID: {
				if (buffer.remaining() >= 4) {
					lastStreamId = buffer.getInt();
					lastStreamId &= 0x7F_FF_FF_FF;
					state = State.ERROR;
					length -= 4;
					if (length <= 0)
						return connectionFailure(buffer, ErrorCode.FRAME_SIZE_ERROR.code, "invalid_go_away_frame");
				} else {
					state = State.LAST_STREAM_ID_BYTES;
					cursor = 4;
				}
				break;
			}
			case LAST_STREAM_ID_BYTES: {
				int currByte = buffer.get() & 0xFF;
				--cursor;
				lastStreamId += currByte << (8 * cursor);
				--length;
				if (cursor > 0 && length <= 0)
					return connectionFailure(buffer, ErrorCode.FRAME_SIZE_ERROR.code, "invalid_go_away_frame");
				if (cursor == 0) {
					lastStreamId &= 0x7F_FF_FF_FF;
					state = State.ERROR;
					if (length == 0)
						return connectionFailure(buffer, ErrorCode.FRAME_SIZE_ERROR.code, "invalid_go_away_frame");
				}
				break;
			}
			case ERROR: {
				if (buffer.remaining() >= 4) {
					error = buffer.getInt();
					state = State.PAYLOAD;
					length -= 4;
					if (length < 0)
						return connectionFailure(buffer, ErrorCode.FRAME_SIZE_ERROR.code, "invalid_go_away_frame");
					if (length == 0)
						return onGoAway(lastStreamId, error, null);
				} else {
					state = State.ERROR_BYTES;
					cursor = 4;
				}
				break;
			}
			case ERROR_BYTES: {
				int currByte = buffer.get() & 0xFF;
				--cursor;
				error += currByte << (8 * cursor);
				--length;
				if (cursor > 0 && length <= 0)
					return connectionFailure(buffer, ErrorCode.FRAME_SIZE_ERROR.code, "invalid_go_away_frame");
				if (cursor == 0) {
					state = State.PAYLOAD;
					if (length == 0)
						return onGoAway(lastStreamId, error, null);
				}
				break;
			}
			case PAYLOAD: {
				payload = new byte[length];
				if (buffer.remaining() >= length) {
					buffer.get(payload);
					return onGoAway(lastStreamId, error, payload);
				} else {
					state = State.PAYLOAD_BYTES;
					cursor = length;
				}
				break;
			}
			case PAYLOAD_BYTES: {
				payload[payload.length - cursor] = buffer.get();
				--cursor;
				if (cursor == 0)
					return onGoAway(lastStreamId, error, payload);
				break;
			}
			default: {
				throw new IllegalStateException();
			}
			}
		}
		return false;
	}

	private boolean onGoAway(int lastStreamId, int error, byte[] payload) {
		GoAwayFrame frame = new GoAwayFrame(lastStreamId, error, payload);
		reset();
		notifyGoAway(frame);
		return true;
	}

	private enum State {
		PREPARE, LAST_STREAM_ID, LAST_STREAM_ID_BYTES, ERROR, ERROR_BYTES, PAYLOAD, PAYLOAD_BYTES
	}
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy