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

org.webpieces.http2translations.api.Http2ToHttp11 Maven / Gradle / Ivy

There is a newer version: 2.1.109
Show newest version
package org.webpieces.http2translations.api;

import java.util.HashSet;
import java.util.Set;

import org.webpieces.httpparser.api.common.Header;
import org.webpieces.httpparser.api.common.KnownHeaderName;
import org.webpieces.httpparser.api.dto.HttpData;
import org.webpieces.httpparser.api.dto.HttpRequest;
import org.webpieces.httpparser.api.dto.HttpRequestLine;
import org.webpieces.httpparser.api.dto.HttpRequestMethod;
import org.webpieces.httpparser.api.dto.HttpResponse;
import org.webpieces.httpparser.api.dto.HttpResponseStatus;
import org.webpieces.httpparser.api.dto.HttpResponseStatusLine;
import org.webpieces.httpparser.api.dto.HttpUri;
import org.webpieces.httpparser.api.dto.KnownStatusCode;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.webpieces.http2.api.dto.highlevel.Http2HeaderStruct;
import com.webpieces.http2.api.dto.highlevel.Http2Request;
import com.webpieces.http2.api.dto.highlevel.Http2Response;
import com.webpieces.http2.api.dto.lowlevel.DataFrame;
import com.webpieces.http2.api.dto.lowlevel.lib.Http2Header;
import com.webpieces.http2.api.dto.lowlevel.lib.Http2HeaderName;

public class Http2ToHttp11 {

	private static final Logger log = LoggerFactory.getLogger(Http2ToHttp11.class);
	
	private static Set headersToSkip = new HashSet<>(); 
	static {
		headersToSkip.add(Http2HeaderName.METHOD.getHeaderName());
		headersToSkip.add(Http2HeaderName.PATH.getHeaderName());
		headersToSkip.add(Http2HeaderName.SCHEME.getHeaderName());
	}
	
	public static HttpResponse translateResponse(Http2Response headers) {

        HttpResponseStatus status = new HttpResponseStatus();
        HttpResponseStatusLine statusLine = new HttpResponseStatusLine();
		statusLine.setStatus(status);
        HttpResponse response = new HttpResponse();
		response.setStatusLine(statusLine);
		
		for(Http2Header header : headers.getHeaders()) {
			if(header.getKnownName() == Http2HeaderName.STATUS) {
				fillStatus(header, status);
			} else if("reason".equals(header.getName())) {
				fillReason(header, status);
			} else if(header.getKnownName() == Http2HeaderName.SCHEME) {
				//do nothing and drop it
			} else {
				Header http1Header = convertHeader(header);
				response.addHeader(http1Header);
			}
		}
		
		if(headers.getHeaderLookupStruct().getHeader(Http2HeaderName.CONTENT_LENGTH) == null) {
			if(headers.isEndOfStream()) {
				//firefox really needs content length!!! if end of stream
				response.addHeader(new Header(KnownHeaderName.CONTENT_LENGTH, "0"));
			} else {
				response.addHeader(new Header(KnownHeaderName.TRANSFER_ENCODING, "chunked"));
			}
		}
		
		if(status.getCode() == null)
			throw new IllegalArgumentException("The header :status is required to send the response");

		//Do a queue instead with last few frames that can be enabled
		log.debug("response="+response);
		
		return response;
	}
	
	private static Header convertHeader(Http2Header header) {
		return new Header(header.getName(), header.getValue());
	}

	private static void fillReason(Http2Header header, HttpResponseStatus status) {
		status.setReason(header.getValue());
	}
	
	private static void fillStatus(Http2Header statusHeader, HttpResponseStatus status) {
        int code = Integer.parseInt(statusHeader.getValue());
        KnownStatusCode knownStatusCode = KnownStatusCode.lookup(code);
        if(knownStatusCode != null) {
        	status.setKnownStatus(knownStatusCode);
        } else {
        	status.setCode(code);
        }		
	}
	
	public static HttpRequest translateRequest(Http2Request headers) {
		
		HttpRequestLine requestLine = new HttpRequestLine();
		
		HttpRequest req = new HttpRequest();
		req.setRequestLine(requestLine);

		for(Http2Header header : headers.getHeaders()) {
			insertInfo(req, header);
		}

		Http2HeaderStruct headerMap = headers.getHeaderLookupStruct();
		Http2Header method = headerMap.getHeader(Http2HeaderName.METHOD);
		if(method == null)
			throw new IllegalArgumentException(Http2HeaderName.METHOD.name()+"is a required header to translate to http1");
		req.getRequestLine().setMethod(new HttpRequestMethod(method.getValue()));
		
		Http2Header host = headerMap.getHeader(Http2HeaderName.AUTHORITY);
		if(host == null)
			throw new IllegalArgumentException(Http2HeaderName.AUTHORITY.name()+"is a required header to translate to http1");

		
		Http2Header path = headerMap.getHeader(Http2HeaderName.PATH);
		if(path == null)
			throw new IllegalArgumentException(Http2HeaderName.PATH.name()+"is a required header to translate to http1");
		
		HttpUri httpUri = new HttpUri(path.getValue());
		req.getRequestLine().setUri(httpUri );
		
		return req;
	}
	
	private static void insertInfo(HttpRequest req, Http2Header header) {
		if(headersToSkip.contains(header.getName()))
			return;

		if(header.getKnownName() == Http2HeaderName.AUTHORITY) {
			//this keeps header order which is sometimes important
			req.addHeader(new Header(KnownHeaderName.HOST, header.getValue()));
			return;
		}
		
		String name = translateName(header.getName());
		req.addHeader(new Header(name, header.getValue()));		
	}
	
	private static String translateName(String name) {
		char[] charArray = name.toCharArray();
		boolean previousDash = false;
		for(int i = 0; i < charArray.length; i++) {
			if(i == 0)
				charArray[i] = Character.toUpperCase(charArray[i]);
			else if(previousDash)
				charArray[i] = Character.toUpperCase(charArray[i]);
			
			if(charArray[i] == '-')
				previousDash = true;
			else
				previousDash = false;
		}
		return new String(charArray);
	}

	public static HttpData translate(DataFrame data, HttpRequest fromRequest) {
		HttpData http11Data = new HttpData(data.getData(), data.isEndOfStream());
		return http11Data;
	}

}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy