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

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

Go to download

A re-usable asynchronous HTTP/2 parser WITH header serialization/deserialization (hpack)

The newest version!
package com.webpieces.hpack.impl;

import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.util.LinkedList;
import java.util.List;

import org.webpieces.data.api.DataWrapper;
import org.webpieces.data.api.DataWrapperGenerator;
import org.webpieces.data.api.DataWrapperGeneratorFactory;
import org.webpieces.util.SneakyThrow;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.twitter.hpack.Encoder;
import com.webpieces.http2.api.dto.highlevel.Http2Headers;
import com.webpieces.http2.api.dto.highlevel.Http2Push;
import com.webpieces.http2.api.dto.lowlevel.ContinuationFrame;
import com.webpieces.http2.api.dto.lowlevel.HeadersFrame;
import com.webpieces.http2.api.dto.lowlevel.PushPromiseFrame;
import com.webpieces.http2.api.dto.lowlevel.lib.HasHeaderFragment;
import com.webpieces.http2.api.dto.lowlevel.lib.Http2Frame;
import com.webpieces.http2.api.dto.lowlevel.lib.Http2Header;

public class HeaderEncoding {
	private static final Logger log = LoggerFactory.getLogger(HeaderEncoding.class);
    private static final DataWrapperGenerator dataGen = DataWrapperGeneratorFactory.createDataWrapperGenerator();
    
	public List translateToFrames(long maxFrameSize, Encoder encoder, Http2Push p) {
		PushPromiseFrame frame = new PushPromiseFrame();
    	frame.setStreamId(p.getStreamId());
    	frame.setPromisedStreamId(p.getPromisedStreamId());
		List headerList = p.getHeaders();
    	
    	List headerFrames = toHeaderFrames(maxFrameSize, encoder, frame, headerList);
		return headerFrames;
	}
	
	public List translateToFrames(long maxFrameSize, Encoder encoder, Http2Headers headers) {
		HeadersFrame frame = new HeadersFrame();
    	frame.setStreamId(headers.getStreamId());
    	frame.setEndOfStream(headers.isEndOfStream());
    	frame.setPriorityDetails(headers.getPriorityDetails());
    	List headerList = headers.getHeaders();
		
    	List headerFrames = toHeaderFrames(maxFrameSize, encoder, frame, headerList);
		return headerFrames;
	}
	
	private List toHeaderFrames(long maxFrameSize, Encoder encoder, HasHeaderFragment firstFrame,
			List headers) {
		
		if(headers.size() == 0)
			throw new IllegalArgumentException("No headers found, at least one required");
					
		List headerFrames = createHeaderFrames(firstFrame, headers, encoder, maxFrameSize);
		
		return headerFrames;
	}
    
    private List createHeaderFrames(HasHeaderFragment initialFrame, List headers, Encoder encoder, long maxFrameSize) {
    	
    	int maxSize = (int) maxFrameSize;
    	if(maxFrameSize > Integer.MAX_VALUE) 
    		throw new IllegalStateException("max frame size too large for this hpack library");
    	
        List headerFrames = new LinkedList<>();
    	
        DataWrapper serializedHeaders = serializeHeaders(encoder, headers);

        HasHeaderFragment currentFrame = initialFrame;
        HasHeaderFragment lastFrame = currentFrame;
        DataWrapper dataLeftOver = serializedHeaders;
        while(dataLeftOver.getReadableSize() > 0) {
            lastFrame = currentFrame;
        	int splitSize = Math.min(dataLeftOver.getReadableSize(), maxSize);
            List split = dataGen.split(dataLeftOver, splitSize);
            DataWrapper fragment = split.get(0);
            
            currentFrame.setHeaderFragment(fragment);
            headerFrames.add(currentFrame);
            
            currentFrame = new ContinuationFrame();
            currentFrame.setStreamId(initialFrame.getStreamId());
            dataLeftOver = split.get(1);
        }

        //last frame is currentFrame so set end header
        lastFrame.setEndHeaders(true);
		return headerFrames;
	}

    private DataWrapper serializeHeaders(Encoder encoder, List headers) {
    	try {
			return serializeHeadersImpl(encoder, headers);
		} catch (IOException e) {
			throw SneakyThrow.sneak(e);
		}
    }
    
    private DataWrapper serializeHeadersImpl(Encoder encoder, List headers) throws IOException {
    	ByteArrayOutputStream out = new ByteArrayOutputStream();
    	synchronized(encoder) {
	        for (Http2Header header : headers) {
	                encoder.encodeHeader(
	                        out,
	                        header.getName().toLowerCase().getBytes(),
	                        header.getValue().getBytes(),
	                        false);
	        }
    	}
        return dataGen.wrapByteArray(out.toByteArray());
    }

	public void setMaxHeaderTableSize(Encoder encoder, int newSize) throws IOException {
		ByteArrayOutputStream out = new ByteArrayOutputStream();
		synchronized(encoder) {
			encoder.setMaxHeaderTableSize(out, newSize);
		}
		log.info("length of out bytes="+out.toByteArray().length);
	}
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy