jetty-9 refactored jetty-http to support injected state

This commit is contained in:
Greg Wilkins 2012-03-13 13:35:48 +11:00
parent e757e5e54d
commit 10cc4ca498
10 changed files with 2270 additions and 965 deletions

View File

@ -533,6 +533,25 @@ public class HttpFields implements Iterable<HttpFields.Field>
_fields.add(field);
_names.put(name, field);
}
/* -------------------------------------------------------------- */
/**
* Set a field.
*
* @param header the header name of the field
* @param value the value of the field. If null the field is cleared.
*/
public void put(HttpHeader header, String value)
{
remove(header.toString());
if (value == null)
return;
// new value;
Field field = new Field(header, value);
_fields.add(field);
_names.put(header.toString(), field);
}
/* -------------------------------------------------------------- */
/**
@ -582,6 +601,38 @@ public class HttpFields implements Iterable<HttpFields.Field>
_names.put(name, field);
}
/* -------------------------------------------------------------- */
/**
* Add to or set a field. If the field is allowed to have multiple values, add will add multiple
* headers of the same name.
*
* @param name the name of the field
* @param value the value of the field.
* @exception IllegalArgumentException If the name is a single valued field and already has a
* value.
*/
public void add(HttpHeader header, String value) throws IllegalArgumentException
{
if (value == null) throw new IllegalArgumentException("null value");
Field field = _names.get(header.toString());
Field last = null;
while (field != null)
{
last = field;
field = field._next;
}
// create the field
field = new Field(header, value);
_fields.add(field);
// look for chain to add too
if (last != null)
last._next = field;
else
_names.put(header.toString(), field);
}
/* ------------------------------------------------------------ */
/**
@ -1051,14 +1102,25 @@ public class HttpFields implements Iterable<HttpFields.Field>
/* ------------------------------------------------------------ */
public static final class Field
{
private final HttpHeader _header;
private final String _name;
private final String _value;
private Field _next;
/* ------------------------------------------------------------ */
private Field(HttpHeader header, String value)
{
_header = header;
_name = header.toString();
_value = value;
_next = null;
}
/* ------------------------------------------------------------ */
private Field(String name, String value)
{
_name = name;
_header = HttpHeader.CACHE.get(name);
_name = _header==null?name:_header.toString();
_value = value;
_next = null;
}
@ -1115,6 +1177,12 @@ public class HttpFields implements Iterable<HttpFields.Field>
buffer.put(toSanitisedBytes(_value));
}
/* ------------------------------------------------------------ */
public HttpHeader getHeader()
{
return _header;
}
/* ------------------------------------------------------------ */
public String getName()
{

View File

@ -29,47 +29,6 @@ import org.eclipse.jetty.util.log.Logger;
*/
public class HttpGenerator
{
// Build cache of response lines for status
private static class Status
{
byte[] _reason;
byte[] _schemeCode;
byte[] _responseLine;
}
private static final Status[] __status = new Status[HttpStatus.MAX_CODE+1];
static
{
int versionLength=HttpVersion.HTTP_1_1.toString().length();
for (int i=0;i<__status.length;i++)
{
HttpStatus.Code code = HttpStatus.getCode(i);
if (code==null)
continue;
String reason=code.getMessage();
byte[] line=new byte[versionLength+5+reason.length()+2];
HttpVersion.HTTP_1_1.toBuffer().get(line,0,versionLength);
line[versionLength+0]=' ';
line[versionLength+1]=(byte)('0'+i/100);
line[versionLength+2]=(byte)('0'+(i%100)/10);
line[versionLength+3]=(byte)('0'+(i%10));
line[versionLength+4]=' ';
for (int j=0;j<reason.length();j++)
line[versionLength+5+j]=(byte)reason.charAt(j);
line[versionLength+5+reason.length()]=HttpTokens.CARRIAGE_RETURN;
line[versionLength+6+reason.length()]=HttpTokens.LINE_FEED;
__status[i] = new Status();
__status[i]._reason=new byte[line.length-versionLength-7] ;
System.arraycopy(line,versionLength+5,__status[i]._reason,0,line.length-versionLength-7);
__status[i]._schemeCode=new byte[versionLength+5];
System.arraycopy(line,0,__status[i]._schemeCode,0,versionLength+5);
__status[i]._responseLine=line;
}
}
private static final Logger LOG = Log.getLogger(HttpGenerator.class);
// states
@ -77,83 +36,82 @@ public class HttpGenerator
public enum Action { FLUSH, COMPLETE, PREPARE };
public enum State { START, COMMITTING, COMMITTING_COMPLETING, COMMITTED, COMPLETING, END };
public enum Result { NEED_CHUNK,NEED_HEADER,NEED_BUFFER,FLUSH,FLUSH_CONTENT,OK,SHUTDOWN_OUT};
public static final byte[] NO_BYTES = {};
// data
private State _state = State.START;
private int _status = 0;
private final HttpFields _fields;
private HttpVersion _version = HttpVersion.HTTP_1_1;
private byte[] _reason;
private byte[] _method;
private byte[] _uri;
private int _largeContent=4096;
private long _contentPrepared = 0;
private long _contentLength = HttpTokens.UNKNOWN_CONTENT;
private boolean _head = false;
private boolean _noContent = false;
private Boolean _persistent = null;
private ByteBuffer _date;
private boolean _sendServerVersion;
// common _content
private static final byte[] LAST_CHUNK = { (byte) '0', (byte) '\015', (byte) '\012', (byte) '\015', (byte) '\012'};
private static final byte[] CONTENT_LENGTH_0 = StringUtil.getBytes("Content-Length: 0\015\012");
private static final byte[] CONNECTION_KEEP_ALIVE = StringUtil.getBytes("Connection: keep-alive\015\012");
private static final byte[] CONNECTION_CLOSE = StringUtil.getBytes("Connection: close\015\012");
private static final byte[] CONNECTION_ = StringUtil.getBytes("Connection: ");
private static final byte[] HTTP_1_1_SPACE = StringUtil.getBytes(HttpVersion.HTTP_1_1+" ");
private static final byte[] CRLF = StringUtil.getBytes("\015\012");
private static final byte[] TRANSFER_ENCODING_CHUNKED = StringUtil.getBytes("Transfer-Encoding: chunked\015\012");
private static byte[] SERVER = StringUtil.getBytes("Server: Jetty(7.0.x)\015\012");
public enum Content { UNKNOWN_CONTENT,NO_CONTENT,EOF_CONTENT,CONTENT_LENGTH,CHUNKED_CONTENT,SELF_DEFINING_CONTENT };
// other statics
public static final int CHUNK_SIZE = 12;
interface Info
{
HttpVersion getHttpVersion();
HttpFields getHttpFields();
boolean isHead();
long getContentLength();
}
interface RequestInfo extends Info
{
String getMethod();
String getURI();
}
interface ResponseInfo extends Info
{
int getStatus();
String getReason();
}
// data
private final Info _info;
private final RequestInfo _request;
private final ResponseInfo _response;
private State _state = State.START;
private Content _content = Content.UNKNOWN_CONTENT;
private int _largeContent=4096;
private long _contentPrepared = 0;
private boolean _noContent = false;
private Boolean _persistent = null;
private boolean _sendServerVersion;
/* ------------------------------------------------------------------------------- */
public static void setServerVersion(String version)
{
SERVER=StringUtil.getBytes("Server: Jetty("+version+")\015\012");
}
/* ------------------------------------------------------------------------------- */
// data
private boolean _needCRLF = false;
/* ------------------------------------------------------------------------------- */
public HttpGenerator(HttpFields fields)
public HttpGenerator(RequestInfo info)
{
_fields=fields;
_info=info;
_request=info;
_response=null;
}
/* ------------------------------------------------------------------------------- */
public HttpGenerator(ResponseInfo info)
{
_info=info;
_request=null;
_response=info;
}
/* ------------------------------------------------------------------------------- */
public void reset()
{
_state = State.START;
_status = 0;
_version = HttpVersion.HTTP_1_1;
_reason = null;
_head = false;
_content = Content.UNKNOWN_CONTENT;
_noContent=false;
_persistent = null;
_contentPrepared = 0;
_contentLength = HttpTokens.UNKNOWN_CONTENT;
_date = null;
_method=null;
_needCRLF = false;
_uri=null;
_noContent=false;
_fields.clear();
}
/* ------------------------------------------------------------ */
@ -186,12 +144,6 @@ public class HttpGenerator
return _state == State.END;
}
/* ------------------------------------------------------------ */
public boolean isIdle()
{
return _state == State.START && _method==null && _status==0;
}
/* ------------------------------------------------------------ */
public boolean isCommitted()
{
@ -201,7 +153,7 @@ public class HttpGenerator
/* ------------------------------------------------------------ */
public boolean isChunking()
{
return _contentLength==HttpTokens.CHUNKED_CONTENT;
return _content==Content.CHUNKED_CONTENT;
}
/* ------------------------------------------------------------ */
@ -216,33 +168,6 @@ public class HttpGenerator
_largeContent = largeContent;
}
/* ------------------------------------------------------------ */
/**
* @return Returns the head.
*/
public boolean isHead()
{
return _head;
}
/* ------------------------------------------------------------ */
public void setContentLength(long value)
{
if (value<0)
_contentLength=HttpTokens.UNKNOWN_CONTENT;
else
_contentLength=value;
}
/* ------------------------------------------------------------ */
/**
* @param head The head to set.
*/
public void setHead(boolean head)
{
_head = head;
}
/* ------------------------------------------------------------ */
/**
* @return <code>false</code> if the connection should be closed after a request has been read,
@ -252,7 +177,7 @@ public class HttpGenerator
{
return _persistent!=null
?_persistent.booleanValue()
:(isRequest()?true:_version.ordinal()>HttpVersion.HTTP_1_0.ordinal());
:(isRequest()?true:_info.getHttpVersion().ordinal()>HttpVersion.HTTP_1_0.ordinal());
}
/* ------------------------------------------------------------ */
@ -261,82 +186,12 @@ public class HttpGenerator
_persistent=persistent;
}
/* ------------------------------------------------------------ */
/**
* @param version The version of the client the response is being sent to (NB. Not the version
* in the response, which is the version of the server).
*/
public void setVersion(HttpVersion version)
{
if (_state != State.START)
throw new IllegalStateException("STATE!=START "+_state);
_version = version;
if (_version==HttpVersion.HTTP_0_9 && _method!=null)
_noContent=true;
}
/* ------------------------------------------------------------ */
public HttpVersion getVersion()
{
return _version;
return _info.getHttpVersion();
}
/* ------------------------------------------------------------ */
/**
* @see org.eclipse.jetty.http.Generator#setDate(org.eclipse.jetty.io.ByteBuffer)
*/
public void setDate(ByteBuffer timeStampBuffer)
{
_date=timeStampBuffer;
}
/* ------------------------------------------------------------ */
/**
*/
public void setRequest(String method, String uri)
{
if (_state != State.START)
throw new IllegalStateException("STATE!=START "+_state);
_method=StringUtil.getBytes(method);
_uri=StringUtil.getUtf8Bytes(uri);
}
/* ------------------------------------------------------------ */
/**
*/
public void setRequest(HttpMethod method, String uri,HttpVersion version)
{
if (_state != State.START)
throw new IllegalStateException("STATE!=START "+_state);
_method=method.getBytes();
_uri=StringUtil.getUtf8Bytes(uri);
setVersion(version);
}
/* ------------------------------------------------------------ */
/**
* @param status The status code to send.
* @param reason the status message to send.
*/
public void setResponse(int status, String reason)
{
if (_state != State.START)
throw new IllegalStateException("STATE!=START");
_method=null;
_status = status;
if (reason==null)
_reason=null;
else
{
if (reason.length()>1024)
reason=reason.substring(0,1024);
_reason=StringUtil.getBytes(reason);
for (int i=_reason.length;i-->0;)
if (_reason[i]=='\r' || _reason[i]=='\n')
_reason[i]='?';
}
}
/* ------------------------------------------------------------ */
public boolean isWritten()
@ -347,10 +202,9 @@ public class HttpGenerator
/* ------------------------------------------------------------ */
public boolean isAllContentWritten()
{
return _contentLength>=0 && _contentPrepared>=_contentLength;
return _content==Content.CONTENT_LENGTH && _contentPrepared>=_info.getContentLength();
}
/* ------------------------------------------------------------ */
public long getContentWritten()
{
@ -360,16 +214,15 @@ public class HttpGenerator
/* ------------------------------------------------------------ */
public boolean isRequest()
{
return _method!=null;
return _request!=null;
}
/* ------------------------------------------------------------ */
public boolean isResponse()
{
return _method==null;
return _response!=null;
}
/* ------------------------------------------------------------ */
public Result generate(ByteBuffer header, ByteBuffer chunk, ByteBuffer buffer, ByteBuffer content, Action action)
{
@ -383,10 +236,10 @@ public class HttpGenerator
if (BufferUtil.hasContent(content))
{
// Do we have too much content?
if (_contentLength>0 && content.remaining()>(_contentLength-_contentPrepared))
if (_content==Content.CONTENT_LENGTH && _info.getContentLength()>=0 && content.remaining()>(_info.getContentLength()-_contentPrepared))
{
LOG.warn("Content truncated at {}",new Throwable());
content.limit(content.position()+(int)(_contentLength-_contentPrepared));
LOG.warn("Content truncated. Info.getContentLength()=="+_info.getContentLength()+" prepared="+_contentPrepared+" content="+content.remaining(),new Throwable());
content.limit(content.position()+(int)(_info.getContentLength()-_contentPrepared));
}
// Can we do a direct flush
@ -478,7 +331,7 @@ public class HttpGenerator
if (header==null || header.capacity()<=CHUNK_SIZE)
return Result.NEED_HEADER;
if(_version==HttpVersion.HTTP_0_9)
if(_info.getHttpVersion()==HttpVersion.HTTP_0_9)
{
_noContent=true;
generateRequestLine(header);
@ -493,10 +346,10 @@ public class HttpGenerator
// Responses
// Do we need a response header?
if (_version == HttpVersion.HTTP_0_9)
if (_info.getHttpVersion() == HttpVersion.HTTP_0_9)
{
_persistent = false;
_contentLength = HttpTokens.EOF_CONTENT;
_content=Content.EOF_CONTENT;
_state = State.COMMITTED;
if (result==Result.FLUSH_CONTENT)
_contentPrepared+=content.remaining();
@ -509,23 +362,24 @@ public class HttpGenerator
// Are we persistent by default?
if (_persistent==null)
_persistent=(_version.ordinal() > HttpVersion.HTTP_1_0.ordinal());
_persistent=(_info.getHttpVersion().ordinal() > HttpVersion.HTTP_1_0.ordinal());
generateResponseLine(header);
// Handle 1xx
if (_status>=100 && _status<200 )
int status=_response.getStatus();
if (status>=100 && status<200 )
{
_noContent=true;
if (_status!=101 )
if (status!=101 )
{
header.put(HttpTokens.CRLF);
_state = State.START;
return Result.OK;
}
}
else if (_status==204 || _status==304)
else if (status==204 || status==304)
{
_noContent=true;
}
@ -650,15 +504,15 @@ public class HttpGenerator
/* ------------------------------------------------------------ */
private void generateRequestLine(ByteBuffer header)
{
header.put(_method);
header.put(StringUtil.getBytes(_request.getMethod()));
header.put((byte)' ');
header.put(_uri);
switch(_version)
header.put(StringUtil.getBytes(_request.getURI()));
switch(_info.getHttpVersion())
{
case HTTP_1_0:
case HTTP_1_1:
header.put((byte)' ');
header.put(_version.toBytes());
header.put(_info.getHttpVersion().toBytes());
}
header.put(HttpTokens.CRLF);
}
@ -667,97 +521,82 @@ public class HttpGenerator
private void generateResponseLine(ByteBuffer header)
{
// Look for prepared response line
Status status = _status<__status.length?__status[_status]:null;
if (status!=null)
int status=_response.getStatus();
PreparedResponse preprepared = status<__preprepared.length?__preprepared[status]:null;
String reason=_response.getReason();
if (preprepared!=null)
{
if (_reason==null)
header.put(status._responseLine);
if (reason==null)
header.put(preprepared._responseLine);
else
{
header.put(status._schemeCode);
header.put(_reason);
header.put(preprepared._schemeCode);
header.put(getReasonBytes(reason));
header.put(HttpTokens.CRLF);
}
}
else // generate response line
{
header.put(HTTP_1_1_SPACE);
header.put((byte) ('0' + _status / 100));
header.put((byte) ('0' + (_status % 100) / 10));
header.put((byte) ('0' + (_status % 10)));
header.put((byte) ('0' + status / 100));
header.put((byte) ('0' + (status % 100) / 10));
header.put((byte) ('0' + (status % 10)));
header.put((byte) ' ');
if (_reason==null)
if (reason==null)
{
header.put((byte) ('0' + _status / 100));
header.put((byte) ('0' + (_status % 100) / 10));
header.put((byte) ('0' + (_status % 10)));
header.put((byte) ('0' + status / 100));
header.put((byte) ('0' + (status % 100) / 10));
header.put((byte) ('0' + (status % 10)));
}
else
header.put(_reason);
header.put(getReasonBytes(reason));
header.put(HttpTokens.CRLF);
}
}
/* ------------------------------------------------------------ */
private byte[] getReasonBytes(String reason)
{
if (reason.length()>1024)
reason=reason.substring(0,1024);
byte[] _bytes = StringUtil.getBytes(reason);
for (int i=_bytes.length;i-->0;)
if (_bytes[i]=='\r' || _bytes[i]=='\n')
_bytes[i]='?';
return _bytes;
}
/* ------------------------------------------------------------ */
private void generateHeaders(ByteBuffer header,ByteBuffer content,boolean last)
{
// Add Date header
if (_status>=200 && _date!=null)
{
header.put(HttpHeader.DATE.getBytesColonSpace());
header.put(_date);
header.put(CRLF);
}
// default field values
boolean has_server = false;
HttpFields.Field transfer_encoding=null;
boolean keep_alive=false;
boolean close=false;
boolean content_type=false;
boolean content_length=false;
StringBuilder connection = null;
// Generate fields
if (_fields != null)
if (_info.getHttpFields() != null)
{
for (HttpFields.Field field : _fields)
for (HttpFields.Field field : _info.getHttpFields())
{
HttpHeader name = HttpHeader.CACHE.get(field.getName());
HttpHeader name = field.getHeader();
switch (name==null?HttpHeader.UNKNOWN:name)
{
case CONTENT_LENGTH:
{
long length = field.getLongValue();
if (length>=0)
{
long prepared=_contentPrepared+BufferUtil.length(content);
if (length < prepared || last && length != prepared)
{
LOG.warn("Incorrect ContentLength: "+length+"!="+prepared);
if (LOG.isDebugEnabled())
LOG.debug(new Throwable());
_contentLength=HttpTokens.UNKNOWN_CONTENT;
}
else
{
// write the field to the header
header.put(HttpHeader.CONTENT_LENGTH.getBytesColonSpace());
BufferUtil.putDecLong(header,length);
BufferUtil.putCRLF(header);
_contentLength=length;
content_length=true;
}
}
// handle specially below
if (_info.getContentLength()>=0)
_content=Content.CONTENT_LENGTH;
break;
}
case CONTENT_TYPE:
{
if (field.getValue().startsWith(MimeTypes.Type.MULTIPART_BYTERANGES.toString()))
_contentLength = HttpTokens.SELF_DEFINING_CONTENT;
_content=Content.SELF_DEFINING_CONTENT;
// write the field to the header
content_type=true;
@ -767,7 +606,7 @@ public class HttpGenerator
case TRANSFER_ENCODING:
{
if (_version == HttpVersion.HTTP_1_1)
if (_info.getHttpVersion() == HttpVersion.HTTP_1_1)
transfer_encoding = field;
// Do NOT add yet!
break;
@ -811,14 +650,14 @@ public class HttpGenerator
close=true;
if (isResponse())
_persistent=false;
if (!_persistent && isResponse() && _contentLength == HttpTokens.UNKNOWN_CONTENT)
_contentLength = HttpTokens.EOF_CONTENT;
if (!_persistent && isResponse() && _content == Content.UNKNOWN_CONTENT)
_content=Content.EOF_CONTENT;
break;
}
case KEEP_ALIVE:
{
if (_version == HttpVersion.HTTP_1_0)
if (_info.getHttpVersion() == HttpVersion.HTTP_1_0)
{
keep_alive = true;
if (isResponse())
@ -877,49 +716,76 @@ public class HttpGenerator
// 4. Content-Length
// 5. multipart/byteranges
// 6. close
switch ((int) _contentLength)
int status=_response!=null?_response.getStatus():-1;
switch (_content)
{
case HttpTokens.UNKNOWN_CONTENT:
case UNKNOWN_CONTENT:
// It may be that we have no _content, or perhaps _content just has not been
// written yet?
// Response known not to have a body
if (_contentPrepared == 0 && isResponse() && (_status < 200 || _status == 204 || _status == 304))
_contentLength = HttpTokens.NO_CONTENT;
else if (last)
if (_contentPrepared == 0 && isResponse() && (status < 200 || status == 204 || status == 304))
_content=Content.NO_CONTENT;
else if (_info.getContentLength()>0)
{
// we have seen all the _content there is
_contentLength = _contentPrepared+BufferUtil.length(content);
if (!content_length && (isResponse() || _contentLength>0 || content_type ) && !_noContent)
// we have been given a content length
_content=Content.CONTENT_LENGTH;
long content_length = _info.getContentLength();
if ((isResponse() || content_length>0 || content_type ) && !_noContent)
{
// known length but not actually set.
header.put(HttpHeader.CONTENT_LENGTH.getBytesColonSpace());
BufferUtil.putDecLong(header, _contentLength);
BufferUtil.putDecLong(header, content_length);
header.put(HttpTokens.CRLF);
}
}
else if (last)
{
// we have seen all the _content there is, so we can be content-length limited.
_content=Content.CONTENT_LENGTH;
long content_length = _contentPrepared+BufferUtil.length(content);
// Do we need to tell the headers about it
if ((isResponse() || content_length>0 || content_type ) && !_noContent)
{
header.put(HttpHeader.CONTENT_LENGTH.getBytesColonSpace());
BufferUtil.putDecLong(header, content_length);
header.put(HttpTokens.CRLF);
}
}
else
{
// No idea, so we must assume that a body is coming
_contentLength = (!_persistent || _version.ordinal() < HttpVersion.HTTP_1_1.ordinal() ) ? HttpTokens.EOF_CONTENT : HttpTokens.CHUNKED_CONTENT;
if (isRequest() && _contentLength==HttpTokens.EOF_CONTENT)
_content = (!_persistent || _info.getHttpVersion().ordinal() < HttpVersion.HTTP_1_1.ordinal() ) ? Content.EOF_CONTENT : Content.CHUNKED_CONTENT;
if (isRequest() && _content==Content.EOF_CONTENT)
{
_contentLength=HttpTokens.NO_CONTENT;
_content=Content.NO_CONTENT;
_noContent=true;
}
}
break;
case HttpTokens.NO_CONTENT:
if (!content_length && isResponse() && _status >= 200 && _status != 204 && _status != 304)
case CONTENT_LENGTH:
long content_length = _info.getContentLength();
if ((isResponse() || content_length>0 || content_type ) && !_noContent)
{
// known length but not actually set.
header.put(HttpHeader.CONTENT_LENGTH.getBytesColonSpace());
BufferUtil.putDecLong(header, content_length);
header.put(HttpTokens.CRLF);
}
break;
case NO_CONTENT:
if (isResponse() && status >= 200 && status != 204 && status != 304)
header.put(CONTENT_LENGTH_0);
break;
case HttpTokens.EOF_CONTENT:
case EOF_CONTENT:
_persistent = isRequest();
break;
case HttpTokens.CHUNKED_CONTENT:
case CHUNKED_CONTENT:
break;
default:
@ -944,7 +810,7 @@ public class HttpGenerator
}
// Handle connection if need be
if (_contentLength==HttpTokens.EOF_CONTENT)
if (_content==Content.EOF_CONTENT)
{
keep_alive=false;
_persistent=false;
@ -953,7 +819,7 @@ public class HttpGenerator
// If this is a response, work out persistence
if (isResponse())
{
if (!_persistent && (close || _version.ordinal() > HttpVersion.HTTP_1_0.ordinal()))
if (!_persistent && (close || _info.getHttpVersion().ordinal() > HttpVersion.HTTP_1_0.ordinal()))
{
if (connection==null)
header.put(CONNECTION_CLOSE);
@ -985,7 +851,7 @@ public class HttpGenerator
}
}
if (!has_server && _status>199 && getSendServerVersion())
if (!has_server && status>199 && getSendServerVersion())
header.put(SERVER);
// end the header.
@ -997,7 +863,7 @@ public class HttpGenerator
/* ------------------------------------------------------------------------------- */
public static byte[] getReasonBuffer(int code)
{
Status status = code<__status.length?__status[code]:null;
PreparedResponse status = code<__preprepared.length?__preprepared[code]:null;
if (status!=null)
return status._reason;
return null;
@ -1011,4 +877,62 @@ public class HttpGenerator
getClass().getSimpleName(),
_state);
}
/* ------------------------------------------------------------------------------- */
/* ------------------------------------------------------------------------------- */
/* ------------------------------------------------------------------------------- */
// common _content
private static final byte[] LAST_CHUNK = { (byte) '0', (byte) '\015', (byte) '\012', (byte) '\015', (byte) '\012'};
private static final byte[] CONTENT_LENGTH_0 = StringUtil.getBytes("Content-Length: 0\015\012");
private static final byte[] CONNECTION_KEEP_ALIVE = StringUtil.getBytes("Connection: keep-alive\015\012");
private static final byte[] CONNECTION_CLOSE = StringUtil.getBytes("Connection: close\015\012");
private static final byte[] CONNECTION_ = StringUtil.getBytes("Connection: ");
private static final byte[] HTTP_1_1_SPACE = StringUtil.getBytes(HttpVersion.HTTP_1_1+" ");
private static final byte[] CRLF = StringUtil.getBytes("\015\012");
private static final byte[] TRANSFER_ENCODING_CHUNKED = StringUtil.getBytes("Transfer-Encoding: chunked\015\012");
private static byte[] SERVER = StringUtil.getBytes("Server: Jetty(7.0.x)\015\012");
private static final byte[] NO_BYTES = {};
/* ------------------------------------------------------------------------------- */
/* ------------------------------------------------------------------------------- */
/* ------------------------------------------------------------------------------- */
// Build cache of response lines for status
private static class PreparedResponse
{
byte[] _reason;
byte[] _schemeCode;
byte[] _responseLine;
}
private static final PreparedResponse[] __preprepared = new PreparedResponse[HttpStatus.MAX_CODE+1];
static
{
int versionLength=HttpVersion.HTTP_1_1.toString().length();
for (int i=0;i<__preprepared.length;i++)
{
HttpStatus.Code code = HttpStatus.getCode(i);
if (code==null)
continue;
String reason=code.getMessage();
byte[] line=new byte[versionLength+5+reason.length()+2];
HttpVersion.HTTP_1_1.toBuffer().get(line,0,versionLength);
line[versionLength+0]=' ';
line[versionLength+1]=(byte)('0'+i/100);
line[versionLength+2]=(byte)('0'+(i%100)/10);
line[versionLength+3]=(byte)('0'+(i%10));
line[versionLength+4]=' ';
for (int j=0;j<reason.length();j++)
line[versionLength+5+j]=(byte)reason.charAt(j);
line[versionLength+5+reason.length()]=HttpTokens.CARRIAGE_RETURN;
line[versionLength+6+reason.length()]=HttpTokens.LINE_FEED;
__preprepared[i] = new PreparedResponse();
__preprepared[i]._reason=new byte[line.length-versionLength-7] ;
System.arraycopy(line,versionLength+5,__preprepared[i]._reason,0,line.length-versionLength-7);
__preprepared[i]._schemeCode=new byte[versionLength+5];
System.arraycopy(line,0,__preprepared[i]._schemeCode,0,versionLength+5);
__preprepared[i]._responseLine=line;
}
}
}

View File

@ -21,6 +21,7 @@ import org.eclipse.jetty.util.BufferUtil;
import org.eclipse.jetty.util.StringUtil;
import org.eclipse.jetty.util.log.Log;
import org.eclipse.jetty.util.log.Logger;
import org.eclipse.jetty.http.HttpGenerator.Content;
public class HttpParser
{
@ -66,6 +67,7 @@ public class HttpParser
private String _field0;
private String _field1;
private byte _eol;
private Content _content;
private long _contentLength;
private long _contentPosition;
private int _chunkLength;
@ -136,7 +138,7 @@ public class HttpParser
/* ------------------------------------------------------------------------------- */
public boolean isChunking()
{
return _contentLength==HttpTokens.CHUNKED_CONTENT;
return _content==Content.CHUNKED_CONTENT;
}
/* ------------------------------------------------------------ */
@ -236,7 +238,7 @@ public class HttpParser
switch (_state)
{
case START:
_contentLength=HttpTokens.UNKNOWN_CONTENT;
_content=Content.UNKNOWN_CONTENT;
_header=null;
if (ch > HttpTokens.SPACE || ch<0)
{
@ -420,7 +422,7 @@ public class HttpParser
switch (_header)
{
case CONTENT_LENGTH:
if (_contentLength != HttpTokens.CHUNKED_CONTENT && _responseStatus!=304 && _responseStatus!=204 && (_responseStatus<100 || _responseStatus>=200))
if (_content != Content.CHUNKED_CONTENT && _responseStatus!=304 && _responseStatus!=204 && (_responseStatus<100 || _responseStatus>=200))
{
try
{
@ -432,17 +434,19 @@ public class HttpParser
throw new HttpException(HttpStatus.BAD_REQUEST_400);
}
if (_contentLength <= 0)
_contentLength=HttpTokens.NO_CONTENT;
_content=Content.NO_CONTENT;
else
_content=Content.CONTENT_LENGTH;
}
break;
case TRANSFER_ENCODING:
if (_value==HttpHeaderValue.CHUNKED)
_contentLength=HttpTokens.CHUNKED_CONTENT;
_content=Content.CHUNKED_CONTENT;
else
{
if (_field1.endsWith(HttpHeaderValue.CHUNKED.toString()))
_contentLength=HttpTokens.CHUNKED_CONTENT;
_content=Content.CHUNKED_CONTENT;
else if (_field1.indexOf(HttpHeaderValue.CHUNKED.toString()) >= 0)
throw new HttpException(400,null);
}
@ -480,7 +484,7 @@ public class HttpParser
}
}
at_next|=_handler.parsedHeader(_field0, _field1);
at_next|=_handler.parsedHeader(_header, _field0, _field1);
}
_field0=_field1=null;
_header=null;
@ -495,32 +499,31 @@ public class HttpParser
// End of headers!
// work out the _content demarcation
if (_contentLength == HttpTokens.UNKNOWN_CONTENT)
if (_content == Content.UNKNOWN_CONTENT)
{
if (_responseStatus == 0 // request
|| _responseStatus == 304 // not-modified response
|| _responseStatus == 204 // no-content response
|| _responseStatus < 200) // 1xx response
_contentLength=HttpTokens.NO_CONTENT;
_content=Content.NO_CONTENT;
else
_contentLength=HttpTokens.EOF_CONTENT;
_content=Content.EOF_CONTENT;
}
// We convert _contentLength to an int for this switch statement because
// we don't care about the amount of data available just whether there is some.
switch (_contentLength > Integer.MAX_VALUE ? Integer.MAX_VALUE : (int) _contentLength)
// How is the message ended?
switch (_content)
{
case HttpTokens.EOF_CONTENT:
case EOF_CONTENT:
_state=State.EOF_CONTENT;
at_next|=_handler.headerComplete(); // May recurse here !
break;
case HttpTokens.CHUNKED_CONTENT:
case CHUNKED_CONTENT:
_state=State.CHUNKED_CONTENT;
at_next|=_handler.headerComplete(); // May recurse here !
break;
case HttpTokens.NO_CONTENT:
case NO_CONTENT:
at_next|=_handler.headerComplete();
_state=_persistent||(_responseStatus>=100&&_responseStatus<200)?State.END:State.SEEKING_EOF;
at_next|=_handler.messageComplete(_contentPosition);
@ -903,7 +906,7 @@ public class HttpParser
{
// reset state
_state=_persistent?State.START:_state==State.END?State.END:State.SEEKING_EOF;
_contentLength=HttpTokens.UNKNOWN_CONTENT;
_content=Content.UNKNOWN_CONTENT;
_contentPosition=0;
_responseStatus=0;
@ -916,7 +919,7 @@ public class HttpParser
public void setState(State state)
{
this._state=state;
_contentLength=HttpTokens.UNKNOWN_CONTENT;
_content=Content.UNKNOWN_CONTENT;
}
@ -948,8 +951,13 @@ public class HttpParser
/**
* This is the method called by parser when a HTTP Header name and value is found
* @param header The HttpHeader value if there is a match
* @param name The String value of the header name
* @param value The String value of the header
* @return
* @throws IOException
*/
public boolean parsedHeader(String name, String value) throws IOException;
public boolean parsedHeader(HttpHeader header, String name, String value) throws IOException;
public boolean earlyEOF();
}

View File

@ -27,11 +27,6 @@ public interface HttpTokens
static final byte SEMI_COLON= (byte)';';
static final byte TAB= 0x09;
public static final int SELF_DEFINING_CONTENT= -4;
public static final int UNKNOWN_CONTENT= -3;
public static final int CHUNKED_CONTENT= -2;
public static final int EOF_CONTENT= -1;
public static final int NO_CONTENT= 0;
}

View File

@ -30,32 +30,88 @@ public class HttpGeneratorClientTest
public final static String CONTENT="The quick brown fox jumped over the lazy dog.\nNow is the time for all good men to come to the aid of the party\nThe moon is blue to a fish in love.\n";
public final static String[] connect={null,"keep-alive","close"};
class Info implements HttpGenerator.RequestInfo
{
final String _method;
final String _uri;
HttpFields _fields = new HttpFields();
long _contentLength = -1;
Info(String method,String uri)
{
_method=method;
_uri=uri;
}
@Override
public HttpVersion getHttpVersion()
{
return HttpVersion.HTTP_1_1;
}
@Override
public HttpFields getHttpFields()
{
return _fields;
}
@Override
public boolean isHead()
{
return false;
}
@Override
public long getContentLength()
{
return _contentLength;
}
public void setContentLength(long l)
{
_contentLength=l;
}
@Override
public String getMethod()
{
return _method;
}
@Override
public String getURI()
{
return _uri;
}
}
@Test
public void testRequestNoContent() throws Exception
{
ByteBuffer header=BufferUtil.allocate(2048);
HttpFields fields = new HttpFields();
HttpGenerator gen = new HttpGenerator(fields);
Info info = new Info("GET","/index.html");
HttpGenerator gen = new HttpGenerator(info);
fields.add("Host","something");
fields.add("User-Agent","test");
gen.setRequest(HttpMethod.GET,"/index.html",HttpVersion.HTTP_1_1);
info.getHttpFields().add("Host","something");
info.getHttpFields().add("User-Agent","test");
HttpGenerator.Result
result=gen.generate(null,null,null,null,Action.COMPLETE);
assertEquals(HttpGenerator.State.COMMITTING_COMPLETING,gen.getState());
assertEquals(HttpGenerator.Result.NEED_HEADER,result);
assertTrue(!gen.isChunking());
result=gen.generate(header,null,null,null,null);
assertEquals(HttpGenerator.Result.FLUSH,result);
assertTrue(!gen.isChunking());
String head = BufferUtil.toString(header);
BufferUtil.clear(header);
result=gen.generate(null,null,null,null,null);
assertEquals(HttpGenerator.Result.OK,result);
assertEquals(HttpGenerator.State.END,gen.getState());
assertTrue(!gen.isChunking());
assertEquals(0,gen.getContentWritten());
assertThat(head,containsString("GET /index.html HTTP/1.1"));
@ -71,13 +127,11 @@ public class HttpGeneratorClientTest
ByteBuffer buffer=BufferUtil.allocate(8096);
ByteBuffer content=BufferUtil.toBuffer("Hello World");
ByteBuffer content1=BufferUtil.toBuffer(". The quick brown fox jumped over the lazy dog.");
HttpFields fields = new HttpFields();
HttpGenerator gen = new HttpGenerator(fields);
Info info = new Info("POST","/index.html");
HttpGenerator gen = new HttpGenerator(info);
gen.setVersion(HttpVersion.HTTP_1_1);
gen.setRequest("POST","/index.html");
fields.add("Host","something");
fields.add("User-Agent","test");
info.getHttpFields().add("Host","something");
info.getHttpFields().add("User-Agent","test");
HttpGenerator.Result
@ -132,13 +186,11 @@ public class HttpGeneratorClientTest
ByteBuffer buffer=BufferUtil.allocate(16);
ByteBuffer content0=BufferUtil.toBuffer("Hello World! ");
ByteBuffer content1=BufferUtil.toBuffer("The quick brown fox jumped over the lazy dog. ");
HttpFields fields = new HttpFields();
HttpGenerator gen = new HttpGenerator(fields);
Info info = new Info("POST","/index.html");
HttpGenerator gen = new HttpGenerator(info);
gen.setVersion(HttpVersion.HTTP_1_1);
gen.setRequest("POST","/index.html");
fields.add("Host","something");
fields.add("User-Agent","test");
info.getHttpFields().add("Host","something");
info.getHttpFields().add("User-Agent","test");
HttpGenerator.Result
@ -242,14 +294,12 @@ public class HttpGeneratorClientTest
ByteBuffer header=BufferUtil.allocate(4096);
ByteBuffer content0=BufferUtil.toBuffer("Hello Cruel World! ");
ByteBuffer content1=BufferUtil.toBuffer("The quick brown fox jumped over the lazy dog. ");
HttpFields fields = new HttpFields();
HttpGenerator gen = new HttpGenerator(fields);
Info info = new Info("POST","/index.html");
HttpGenerator gen = new HttpGenerator(info);
gen.setLargeContent(8);
gen.setVersion(HttpVersion.HTTP_1_1);
gen.setRequest("POST","/index.html");
fields.add("Host","something");
fields.add("User-Agent","test");
info.getHttpFields().add("Host","something");
info.getHttpFields().add("User-Agent","test");
HttpGenerator.Result
@ -315,15 +365,13 @@ public class HttpGeneratorClientTest
ByteBuffer buffer=BufferUtil.allocate(16);
ByteBuffer content0=BufferUtil.toBuffer("Hello World! ");
ByteBuffer content1=BufferUtil.toBuffer("The quick brown fox jumped over the lazy dog. ");
HttpFields fields = new HttpFields();
HttpGenerator gen = new HttpGenerator(fields);
Info info = new Info("POST","/index.html");
HttpGenerator gen = new HttpGenerator(info);
gen.setVersion(HttpVersion.HTTP_1_1);
gen.setRequest("POST","/index.html");
fields.add("Host","something");
fields.add("User-Agent","test");
fields.add("Content-Length","59");
gen.setContentLength(59);
info.getHttpFields().add("Host","something");
info.getHttpFields().add("User-Agent","test");
info.getHttpFields().add("Content-Length","59");
info.setContentLength(59);
HttpGenerator.Result
@ -408,16 +456,14 @@ public class HttpGeneratorClientTest
ByteBuffer header=BufferUtil.allocate(4096);
ByteBuffer content0=BufferUtil.toBuffer("Hello World! ");
ByteBuffer content1=BufferUtil.toBuffer("The quick brown fox jumped over the lazy dog. ");
HttpFields fields = new HttpFields();
HttpGenerator gen = new HttpGenerator(fields);
Info info = new Info("POST","/index.html");
HttpGenerator gen = new HttpGenerator(info);
gen.setLargeContent(8);
gen.setVersion(HttpVersion.HTTP_1_1);
gen.setRequest("POST","/index.html");
fields.add("Host","something");
fields.add("User-Agent","test");
fields.add("Content-Length","59");
gen.setContentLength(59);
info.getHttpFields().add("Host","something");
info.getHttpFields().add("User-Agent","test");
info.getHttpFields().add("Content-Length","59");
info.setContentLength(59);
HttpGenerator.Result

View File

@ -303,7 +303,7 @@ public class HttpParserTest
assertEquals("HTTP/1.1", f0);
assertEquals("200", f1);
assertEquals("Correct", f2);
assertEquals(_content.length(), 10);
assertEquals(10,_content.length());
assertTrue(headerCompleted);
assertTrue(messageCompleted);
}
@ -477,16 +477,15 @@ public class HttpParserTest
}
@Override
public boolean startRequest(String tok0, String tok1, String tok2)
public boolean startRequest(String method, String uri, String version)
{
//System.err.println("request "+tok0+" "+tok1+" "+tok2);
request=true;
h= -1;
hdr= new String[9];
val= new String[9];
f0= tok0;
f1= tok1;
f2= tok2;
f0= method;
f1= uri;
f2= version;
fields=new HttpFields();
messageCompleted = false;
@ -495,7 +494,7 @@ public class HttpParserTest
}
@Override
public boolean parsedHeader(String name, String value)
public boolean parsedHeader(HttpHeader header, String name, String value)
{
//System.err.println("header "+name+": "+value);
hdr[++h]= name;

View File

@ -24,12 +24,21 @@ import java.io.IOException;
import java.net.ServerSocket;
import java.net.Socket;
import java.net.SocketException;
import java.nio.ByteBuffer;
import java.nio.channels.AsynchronousServerSocketChannel;
import java.nio.channels.AsynchronousSocketChannel;
import java.nio.channels.SelectionKey;
import java.nio.channels.Selector;
import java.nio.channels.ServerSocketChannel;
import java.nio.channels.SocketChannel;
import java.nio.channels.spi.SelectorProvider;
import java.util.Set;
import java.util.concurrent.Future;
import junit.framework.Assert;
import org.eclipse.jetty.toolchain.test.OS;
import org.eclipse.jetty.util.BufferUtil;
import org.eclipse.jetty.util.IO;
import org.junit.Test;
@ -292,7 +301,7 @@ public class IOTest
client.setSoLinger(true,0);
server.setTcpNoDelay(true);
server.setSoLinger(true,0);
client.getOutputStream().write(1);
assertEquals(1,server.getInputStream().read());
server.getOutputStream().write(1);
@ -318,5 +327,32 @@ public class IOTest
// Since output was already shutdown, server closes
server.close();
}
@Test
public void testAsyncSocketChannel() throws Exception
{
AsynchronousServerSocketChannel connector = AsynchronousServerSocketChannel.open();
connector.bind(null);
Future<AsynchronousSocketChannel> acceptor= connector.accept();
AsynchronousSocketChannel client = AsynchronousSocketChannel.open();
client.connect(connector.getLocalAddress());
AsynchronousSocketChannel server = acceptor.get();
ByteBuffer read = ByteBuffer.allocate(1024);
Future<Integer> reading=server.read(read);
ByteBuffer write= BufferUtil.toBuffer("Testing 1 2 3");
Future<Integer> writing=client.write(write);
reading.get();
writing.get();
read.flip();
System.err.println(BufferUtil.toString(read));
}
}

File diff suppressed because it is too large Load Diff

View File

@ -378,8 +378,8 @@ public class Response implements HttpServletResponse
}
else if (code!=SC_PARTIAL_CONTENT)
{
_connection.getRequestFields().remove(HttpHeader.CONTENT_TYPE_BUFFER);
_connection.getRequestFields().remove(HttpHeader.CONTENT_LENGTH_BUFFER);
_connection.getRequestFields().remove(HttpHeader.CONTENT_TYPE);
_connection.getRequestFields().remove(HttpHeader.CONTENT_LENGTH);
_characterEncoding=null;
_mimeType=null;
_cachedMimeType=null;
@ -727,9 +727,9 @@ public class Response implements HttpServletResponse
{
_characterEncoding=null;
if (_cachedMimeType!=null)
_connection.getResponseFields().put(HttpHeader.CONTENT_TYPE_BUFFER,_cachedMimeType);
_connection.getResponseFields().put(HttpHeader.CONTENT_TYPE,_cachedMimeType);
else
_connection.getResponseFields().put(HttpHeader.CONTENT_TYPE_BUFFER,_mimeType);
_connection.getResponseFields().put(HttpHeader.CONTENT_TYPE,_mimeType);
}
}
else
@ -748,14 +748,14 @@ public class Response implements HttpServletResponse
if (content_type!=null)
{
_contentType=content_type.toString();
_connection.getResponseFields().put(HttpHeader.CONTENT_TYPE_BUFFER,content_type);
_connection.getResponseFields().put(HttpHeader.CONTENT_TYPE,content_type);
}
}
if (_contentType==null)
{
_contentType = _mimeType+";charset="+QuotedStringTokenizer.quoteIfNeeded(_characterEncoding,";= ");
_connection.getResponseFields().put(HttpHeader.CONTENT_TYPE_BUFFER,_contentType);
_connection.getResponseFields().put(HttpHeader.CONTENT_TYPE,_contentType);
}
}
else
@ -774,7 +774,7 @@ public class Response implements HttpServletResponse
else
_contentType=_contentType.substring(0,i8)+QuotedStringTokenizer.quoteIfNeeded(_characterEncoding,";= ")+_contentType.substring(i2);
}
_connection.getResponseFields().put(HttpHeader.CONTENT_TYPE_BUFFER,_contentType);
_connection.getResponseFields().put(HttpHeader.CONTENT_TYPE,_contentType);
}
}
}
@ -850,7 +850,7 @@ public class Response implements HttpServletResponse
_mimeType=null;
_cachedMimeType=null;
_contentType=null;
_connection.getResponseFields().remove(HttpHeader.CONTENT_TYPE_BUFFER);
_connection.getResponseFields().remove(HttpHeader.CONTENT_TYPE);
}
else
{
@ -884,29 +884,29 @@ public class Response implements HttpServletResponse
if (content_type!=null)
{
_contentType=content_type.toString();
_connection.getResponseFields().put(HttpHeader.CONTENT_TYPE_BUFFER,content_type);
_connection.getResponseFields().put(HttpHeader.CONTENT_TYPE,content_type);
}
else
{
_contentType=_mimeType+";charset="+_characterEncoding;
_connection.getResponseFields().put(HttpHeader.CONTENT_TYPE_BUFFER,_contentType);
_connection.getResponseFields().put(HttpHeader.CONTENT_TYPE,_contentType);
}
}
else
{
_contentType=_mimeType+";charset="+_characterEncoding;
_connection.getResponseFields().put(HttpHeader.CONTENT_TYPE_BUFFER,_contentType);
_connection.getResponseFields().put(HttpHeader.CONTENT_TYPE,_contentType);
}
}
else if (i2<0)
{
_contentType=contentType.substring(0,i1)+";charset="+QuotedStringTokenizer.quoteIfNeeded(_characterEncoding,";= ");
_connection.getResponseFields().put(HttpHeader.CONTENT_TYPE_BUFFER,_contentType);
_connection.getResponseFields().put(HttpHeader.CONTENT_TYPE,_contentType);
}
else
{
_contentType=contentType.substring(0,i1)+contentType.substring(i2)+";charset="+QuotedStringTokenizer.quoteIfNeeded(_characterEncoding,";= ");
_connection.getResponseFields().put(HttpHeader.CONTENT_TYPE_BUFFER,_contentType);
_connection.getResponseFields().put(HttpHeader.CONTENT_TYPE,_contentType);
}
}
else if ((i1==i0+1 && i2<0) || (i1==i0+2 && i2<0 && contentType.charAt(i0+1)==' '))
@ -921,38 +921,38 @@ public class Response implements HttpServletResponse
if (content_type!=null)
{
_contentType=content_type.toString();
_connection.getResponseFields().put(HttpHeader.CONTENT_TYPE_BUFFER,content_type);
_connection.getResponseFields().put(HttpHeader.CONTENT_TYPE,content_type);
}
else
{
_contentType=contentType;
_connection.getResponseFields().put(HttpHeader.CONTENT_TYPE_BUFFER,_contentType);
_connection.getResponseFields().put(HttpHeader.CONTENT_TYPE,_contentType);
}
}
else
{
_contentType=contentType;
_connection.getResponseFields().put(HttpHeader.CONTENT_TYPE_BUFFER,_contentType);
_connection.getResponseFields().put(HttpHeader.CONTENT_TYPE,_contentType);
}
}
else if (i2>0)
{
_characterEncoding = QuotedStringTokenizer.unquote(contentType.substring(i8,i2));
_contentType=contentType;
_connection.getResponseFields().put(HttpHeader.CONTENT_TYPE_BUFFER,_contentType);
_connection.getResponseFields().put(HttpHeader.CONTENT_TYPE,_contentType);
}
else
{
_characterEncoding = QuotedStringTokenizer.unquote(contentType.substring(i8));
_contentType=contentType;
_connection.getResponseFields().put(HttpHeader.CONTENT_TYPE_BUFFER,_contentType);
_connection.getResponseFields().put(HttpHeader.CONTENT_TYPE,_contentType);
}
}
else // No encoding in the params.
{
_cachedMimeType=null;
_contentType=_characterEncoding==null?contentType:contentType+";charset="+QuotedStringTokenizer.quoteIfNeeded(_characterEncoding,";= ");
_connection.getResponseFields().put(HttpHeader.CONTENT_TYPE_BUFFER,_contentType);
_connection.getResponseFields().put(HttpHeader.CONTENT_TYPE,_contentType);
}
}
else // No params at all
@ -968,29 +968,29 @@ public class Response implements HttpServletResponse
if (content_type!=null)
{
_contentType=content_type.toString();
_connection.getResponseFields().put(HttpHeader.CONTENT_TYPE_BUFFER,content_type);
_connection.getResponseFields().put(HttpHeader.CONTENT_TYPE,content_type);
}
else
{
_contentType=_mimeType+";charset="+QuotedStringTokenizer.quoteIfNeeded(_characterEncoding,";= ");
_connection.getResponseFields().put(HttpHeader.CONTENT_TYPE_BUFFER,_contentType);
_connection.getResponseFields().put(HttpHeader.CONTENT_TYPE,_contentType);
}
}
else
{
_contentType=contentType+";charset="+QuotedStringTokenizer.quoteIfNeeded(_characterEncoding,";= ");
_connection.getResponseFields().put(HttpHeader.CONTENT_TYPE_BUFFER,_contentType);
_connection.getResponseFields().put(HttpHeader.CONTENT_TYPE,_contentType);
}
}
else if (_cachedMimeType!=null)
{
_contentType=_cachedMimeType.toString();
_connection.getResponseFields().put(HttpHeader.CONTENT_TYPE_BUFFER,_cachedMimeType);
_connection.getResponseFields().put(HttpHeader.CONTENT_TYPE,_cachedMimeType);
}
else
{
_contentType=contentType;
_connection.getResponseFields().put(HttpHeader.CONTENT_TYPE_BUFFER,_contentType);
_connection.getResponseFields().put(HttpHeader.CONTENT_TYPE,_contentType);
}
}
}
@ -1039,7 +1039,7 @@ public class Response implements HttpServletResponse
HttpFields response_fields=_connection.getResponseFields();
response_fields.clear();
String connection=_connection.getRequestFields().getStringField(HttpHeader.CONNECTION_BUFFER);
String connection=_connection.getRequestFields().getStringField(HttpHeader.CONNECTION);
if (connection!=null)
{
String[] values = connection.split(",");
@ -1052,15 +1052,15 @@ public class Response implements HttpServletResponse
switch(cb.getOrdinal())
{
case HttpHeaderValue.CLOSE_ORDINAL:
response_fields.put(HttpHeader.CONNECTION_BUFFER,HttpHeaderValue.CLOSE_BUFFER);
response_fields.put(HttpHeader.CONNECTION,HttpHeaderValue.CLOSE);
break;
case HttpHeaderValue.KEEP_ALIVE_ORDINAL:
if (HttpVersion.HTTP_1_0.equalsIgnoreCase(_connection.getRequest().getProtocol()))
response_fields.put(HttpHeader.CONNECTION_BUFFER,HttpHeaderValue.KEEP_ALIVE);
response_fields.put(HttpHeader.CONNECTION,HttpHeaderValue.KEEP_ALIVE);
break;
case HttpHeaderValue.TE_ORDINAL:
response_fields.put(HttpHeader.CONNECTION_BUFFER,HttpHeaderValue.TE);
response_fields.put(HttpHeader.CONNECTION,HttpHeaderValue.TE);
break;
}
}
@ -1111,7 +1111,7 @@ public class Response implements HttpServletResponse
return;
_locale = locale;
_connection.getResponseFields().put(HttpHeader.CONTENT_LANGUAGE_BUFFER,locale.toString().replace('_','-'));
_connection.getResponseFields().put(HttpHeader.CONTENT_LANGUAGE,locale.toString().replace('_','-'));
if (_explicitEncoding || _outputState!=0 )
return;
@ -1143,7 +1143,7 @@ public class Response implements HttpServletResponse
}
_cachedMimeType=MimeTypes.CACHE.get(_mimeType);
_connection.getResponseFields().put(HttpHeader.CONTENT_TYPE_BUFFER,_contentType);
_connection.getResponseFields().put(HttpHeader.CONTENT_TYPE,_contentType);
}
}
}