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

com.webpieces.hpack.impl.HeaderDecoding Maven / Gradle / Ivy

package com.webpieces.hpack.impl;

import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import java.util.function.Consumer;

import org.webpieces.data.api.DataWrapper;

import com.twitter.hpack.Decoder;
import com.webpieces.http2.api.dto.error.CancelReasonCode;
import com.webpieces.http2.api.dto.error.ConnectionException;
import com.webpieces.http2.api.dto.lowlevel.lib.Http2Header;
import com.webpieces.http2.api.dto.lowlevel.lib.Http2HeaderName;

public class HeaderDecoding {

	public void setMaxHeaderTableSize(Decoder decoder, int newSize) {
		synchronized(decoder) {
			decoder.setMaxHeaderTableSize(newSize);
		}
	}

	public List decode(UnmarshalStateImpl state, DataWrapper data, int streamId, Consumer knownHeaders) {
		try {
			return decodeImpl(state, data, streamId, knownHeaders);
        } catch (IOException e) {
            // TODO: this doesn't catch the h2spec -s 4.3 invalid header block fragment
            throw new ConnectionException(CancelReasonCode.HEADER_DECODE, state.getLogId(), streamId, "Error from hpack library", e);
            //TODO: clone hpack and fix so they throw with debug info as their errors contain no info :(
        }
	}
	
	private List decodeImpl(UnmarshalStateImpl state, DataWrapper data, int streamId, Consumer knownHeaders) throws IOException {
        List headers = new ArrayList<>();
        byte[] bytes = data.createByteArray();
        ByteArrayInputStream in = new ByteArrayInputStream(bytes);
        	
        Decoder decoder = state.getDecoder();
        
        //TODO(dhiller): make this an async syncrhonized block instead so threads can keep running!!!
		synchronized(decoder) {
	        decoder.decode(in, (n, v, s) -> addToHeaders(headers, knownHeaders, n, v, s, state.getLogId(), streamId));
	        decoder.endHeaderBlock();
		}
	
        if(data.getReadableSize() > 0 && headers.size() == 0)
        	throw new ConnectionException(CancelReasonCode.COMPRESSION_ERROR, state.getLogId(), streamId, "Header data came in, but no headers came out");

        return headers;
    }

	private Object addToHeaders(
			List headers, Consumer knownHeaders, 
			byte[] name, byte[] value, boolean sensitive, String logId, int streamId) {
        String h = new String(name);
        String v = new String(value);
        if(!h.equals(h.toLowerCase()))
            throw new ConnectionException(CancelReasonCode.HEADER_NOT_LOWER_CASE, logId, streamId, "header="+h+" was not lower case in stream="+streamId);
        
        Http2Header header = new Http2Header(h, v);
        headers.add(header);
        
        if(knownHeaders != null) {
        	Http2HeaderName knownName = Http2HeaderName.lookup(h);
        	if(knownName != null)
        		knownHeaders.accept(header);
        }
		return null;
	}

}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy