blob: 8e81dccaf838a1a1ced7cadbac22c8ded6789746 [file] [log] [blame]
//
// ========================================================================
// Copyright (c) 1995-2015 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.hpack;
import org.eclipse.jetty.http.BadMessageException;
import org.eclipse.jetty.http.HostPortHttpField;
import org.eclipse.jetty.http.HttpField;
import org.eclipse.jetty.http.HttpFields;
import org.eclipse.jetty.http.HttpScheme;
import org.eclipse.jetty.http.HttpStatus;
import org.eclipse.jetty.http.HttpVersion;
import org.eclipse.jetty.http.MetaData;
public class MetaDataBuilder
{
private final int _maxSize;
private int _size;
private int _status;
private String _method;
private HttpScheme _scheme;
private HostPortHttpField _authority;
private String _path;
private long _contentLength=Long.MIN_VALUE;
private HttpFields _fields = new HttpFields(10);
/* ------------------------------------------------------------ */
/**
* @param maxHeadersSize The maximum size of the headers, expressed as total name and value characters.
*/
MetaDataBuilder(int maxHeadersSize)
{
_maxSize=maxHeadersSize;
}
/** Get the maxSize.
* @return the maxSize
*/
public int getMaxSize()
{
return _maxSize;
}
/** Get the size.
* @return the current size in bytes
*/
public int getSize()
{
return _size;
}
public void emit(HttpField field)
{
int field_size = field.getName().length()+field.getValue().length();
_size+=field_size;
if (_size>_maxSize)
throw new BadMessageException(HttpStatus.REQUEST_ENTITY_TOO_LARGE_413,"Header size "+_size+">"+_maxSize);
if (field instanceof StaticTableHttpField)
{
StaticTableHttpField value = (StaticTableHttpField)field;
switch(field.getHeader())
{
case C_STATUS:
_status=(Integer)value.getStaticValue();
break;
case C_METHOD:
_method=field.getValue();
break;
case C_SCHEME:
_scheme = (HttpScheme)value.getStaticValue();
break;
default:
throw new IllegalArgumentException(field.getName());
}
}
else if (field.getHeader()!=null)
{
switch(field.getHeader())
{
case C_STATUS:
_status=field.getIntValue();
break;
case C_METHOD:
_method=field.getValue();
break;
case C_SCHEME:
_scheme = HttpScheme.CACHE.get(field.getValue());
break;
case C_AUTHORITY:
_authority=(field instanceof HostPortHttpField)?((HostPortHttpField)field):new AuthorityHttpField(field.getValue());
break;
case HOST:
// :authority fields must come first. If we have one, ignore the host header as far as authority goes.
if (_authority==null)
_authority=(field instanceof HostPortHttpField)?((HostPortHttpField)field):new AuthorityHttpField(field.getValue());
_fields.add(field);
break;
case C_PATH:
_path = field.getValue();
break;
case CONTENT_LENGTH:
_contentLength = field.getLongValue();
_fields.add(field);
break;
default:
if (field.getName().charAt(0)!=':')
_fields.add(field);
}
}
else
{
if (field.getName().charAt(0)!=':')
_fields.add(field);
}
}
public MetaData build()
{
try
{
HttpFields fields = _fields;
_fields = new HttpFields(Math.max(10,fields.size()+5));
if (_method!=null)
return new MetaData.Request(_method,_scheme,_authority,_path,HttpVersion.HTTP_2,fields,_contentLength);
if (_status!=0)
return new MetaData.Response(HttpVersion.HTTP_2,_status,fields,_contentLength);
return new MetaData(HttpVersion.HTTP_2,fields,_contentLength);
}
finally
{
_status=0;
_method=null;
_scheme=null;
_authority=null;
_path=null;
_size=0;
_contentLength=Long.MIN_VALUE;
}
}
/* ------------------------------------------------------------ */
/** Check that the max size will not be exceeded.
* @param length the length
* @param huffman the huffman name
*/
public void checkSize(int length, boolean huffman)
{
// Apply a huffman fudge factor
if (huffman)
length=(length*4)/3;
if ((_size+length)>_maxSize)
throw new BadMessageException(HttpStatus.REQUEST_ENTITY_TOO_LARGE_413,"Header size "+(_size+length)+">"+_maxSize);
}
}