
com.caucho.v5.http.protocol.RequestHttpBase Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of baratine Show documentation
Show all versions of baratine Show documentation
A reactive Java web server.
/*
* Copyright (c) 1998-2015 Caucho Technology -- all rights reserved
*
* This file is part of Baratine(TM)
*
* Each copy or derived work must preserve the copyright notice and this
* notice unmodified.
*
* Baratine is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* Baratine is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE, or any warranty
* of NON-INFRINGEMENT. See the GNU General Public License for more
* details.
*
* You should have received a copy of the GNU General Public License
* along with Baratine; if not, write to the
*
* Free Software Foundation, Inc.
* 59 Temple Place, Suite 330
* Boston, MA 02111-1307 USA
*
* @author Scott Ferguson
*/
package com.caucho.v5.http.protocol;
import java.io.IOException;
import java.net.InetAddress;
import java.time.Instant;
import java.time.OffsetDateTime;
import java.time.ZoneOffset;
import java.time.format.DateTimeFormatter;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.Enumeration;
import java.util.HashSet;
import java.util.Locale;
import java.util.Objects;
import java.util.concurrent.ConcurrentHashMap;
import java.util.logging.Level;
import java.util.logging.Logger;
import com.caucho.v5.health.meter.CountSensor;
import com.caucho.v5.health.meter.MeterService;
import com.caucho.v5.http.container.HttpContainer;
import com.caucho.v5.http.dispatch.Invocation;
import com.caucho.v5.http.dispatch.InvocationDecoder;
import com.caucho.v5.http.dispatch.InvocationManager;
import com.caucho.v5.http.log.LogBuffer;
import com.caucho.v5.io.IoUtil;
import com.caucho.v5.io.WriteBuffer;
import com.caucho.v5.io.i18n.Encoding;
import com.caucho.v5.network.port.ConnectionProtocol;
import com.caucho.v5.network.port.ConnectionTcp;
import com.caucho.v5.util.CaseInsensitiveIntMap;
import com.caucho.v5.util.CharBuffer;
import com.caucho.v5.util.CharSegment;
import com.caucho.v5.util.ClockCurrent;
import com.caucho.v5.util.L10N;
import com.caucho.v5.util.LruCache;
import com.caucho.v5.web.CookieWeb;
/**
* Abstract request implementing methods common to the different
* request implementations.
*/
public abstract class RequestHttpBase implements OutHttp
{
private static final Logger log
= Logger.getLogger(RequestHttpBase.class.getName());
private static final L10N L = new L10N(RequestHttpBase.class);
protected static final CaseInsensitiveIntMap _headerCodes;
public static final String JSP_EXCEPTION = "javax.servlet.jsp.jspException";
public static final String SHUTDOWN = "com.caucho.shutdown";
private static final char []CONNECTION = "connection".toCharArray();
private static final char []COOKIE = "cookie".toCharArray();
private static final char []CONTENT_LENGTH = "content-length".toCharArray();
private static final char []EXPECT = "expect".toCharArray();
private static final char []HOST = "host".toCharArray();
private static final char []TRANSFER_ENCODING = "transfer-encoding".toCharArray();
private static final char []X_FORWARDED_HOST = "x-forwarded-host".toCharArray();
private static final int CONNECTION_KEY
= 'c' | (10 << 8);
private static final int COOKIE_KEY
= 'c' | (6 << 8);
private static final int CONTENT_LENGTH_KEY
= 'c' | (14 << 8);
private static final int EXPECT_KEY
= 'e' | (6 << 8);
private static final int HOST_KEY
= 'h' | (4 << 8);
private static final int TRANSFER_ENCODING_KEY
= 't' | (17 << 8);
private static final int X_FORWARDED_HOST_KEY
= 'x' | (16 << 8);
private static final char []CONTINUE_100 = "100-continue".toCharArray();
private static final char []CLOSE = "close".toCharArray();
private static final char []KEEPALIVE = "keep-alive".toCharArray();
private static final char []UPGRADE = "Upgrade".toCharArray();
private static final CharBuffer CACHE_CONTROL_CB
= new CharBuffer("cache-control");
private static final CharBuffer CONNECTION_CB
= new CharBuffer("connection");
private static final CharBuffer CONTENT_TYPE_CB
= new CharBuffer("content-type");
private static final CharBuffer CONTENT_LENGTH_CB
= new CharBuffer("content-length");
private static final CharBuffer DATE_CB
= new CharBuffer("date");
private static final CharBuffer SERVER_CB
= new CharBuffer("server");
public static final boolean []TOKEN;
private static final boolean []VALUE;
private static final CookieWeb []NULL_COOKIES = new CookieWeb[0];
private static final CountSensor _statusXxxSensor
= MeterService.createCountMeter("Caucho|Http|xxx");
private static final CountSensor _status2xxSensor
= MeterService.createCountMeter("Caucho|Http|2xx");
private static final CountSensor _status200Sensor
= MeterService.createCountMeter("Caucho|Http|200");
private static final CountSensor _status3xxSensor
= MeterService.createCountMeter("Caucho|Http|3xx");
private static final CountSensor _status304Sensor
= MeterService.createCountMeter("Caucho|Http|304");
private static final CountSensor _status4xxSensor
= MeterService.createCountMeter("Caucho|Http|4xx");
private static final CountSensor _status400Sensor
= MeterService.createCountMeter("Caucho|Http|400");
private static final CountSensor _status404Sensor
= MeterService.createCountMeter("Caucho|Http|404");
private static final CountSensor _status5xxSensor
= MeterService.createCountMeter("Caucho|Http|5xx");
private static final CountSensor _status500Sensor
= MeterService.createCountMeter("Caucho|Http|500");
private static final CountSensor _status503Sensor
= MeterService.createCountMeter("Caucho|Http|503");
//private static final CaseInsensitiveIntMap _headerCodes;
private static final CharBuffer CACHE_CONTROL
= new CharBuffer("cache-control");
//private static final CharBuffer CONNECTION
//= new CharBuffer("connection");
private static final CharBuffer CONTENT_TYPE
= new CharBuffer("content-type");
//private static final CharBuffer CONTENT_LENGTH
//= new CharBuffer("content-length");
private static final CharBuffer DATE
= new CharBuffer("date");
private static final CharBuffer SERVER
= new CharBuffer("server");
private static final long MINUTE = 60 * 1000L;
private static final long HOUR = 60 * MINUTE;
private static final ConcurrentHashMap _contentTypeMap
= new ConcurrentHashMap<>();
private static final LruCache _nameCache
= new LruCache<>(1024);
private static final int HEADER_CACHE_CONTROL = 1;
private static final int HEADER_CONTENT_TYPE = HEADER_CACHE_CONTROL + 1;
private static final int HEADER_CONTENT_LENGTH = HEADER_CONTENT_TYPE + 1;
private static final int HEADER_DATE = HEADER_CONTENT_LENGTH + 1;
private static final int HEADER_SERVER = HEADER_DATE + 1;
private static final int HEADER_CONNECTION = HEADER_SERVER + 1;
private static DateTimeFormatter _dateFormatter;
private final ProtocolHttp _protocolHttp;
private final InvocationKey _invocationKey = new InvocationKey();
// Connection stream
//private final ReadStream _rawRead;
// Stream for reading post contents
//private final ReadStream _readStream;
private final ArrayList _cookies = new ArrayList<>();
// Servlet input stream for post contents
//private final ServletInputStreamImpl _is = new ServletInputStreamImpl(this);
// Reader for post contents
//private final BufferedReaderAdapter _bufferedReader;
// private ErrorPageManager _errorManager;
// Efficient date class for printing date headers
// private final QDate _calendar = new QDate();
private final CharBuffer _cbName = new CharBuffer();
private final CharBuffer _cbValue = new CharBuffer();
private final CharBuffer _cb = new CharBuffer();
private byte []_smallUriBuffer = new byte[256];
private char []_smallHeaderBuffer = new char[1024];
private CharSegment []_smallHeaderKeys = new CharSegment[32];
private CharSegment []_smallHeaderValues = new CharSegment[32];
private HttpBufferStore _largeHttpBuffer;
//private RequestFacade _requestFacade;
private ConnectionTcp _conn;
private ConnectionHttp _connHttp;
private long _startTime;
private long _expireTime;
private CharSegment _hostHeader;
private CharSegment _xForwardedHostHeader;
private boolean _expect100Continue;
private long _contentLengthIn = -1;
// True if the post stream has been initialized
private boolean _hasReadStream;
// character incoding for a Post
private String _readEncoding;
private boolean _isUpgrade;
//
// output data
//
private int _statusCode = 200;
private String _statusMessage = "OK";
private final ArrayList _headerKeys = new ArrayList<>();
private final ArrayList _headerValues = new ArrayList<>();
private final ArrayList _footerKeys = new ArrayList<>();
private final ArrayList _footerValues = new ArrayList<>();
private OutResponseBase _responseStream;
private final LogBuffer _logBuffer;
private final byte []_dateBuffer = new byte[64];
private final CharBuffer _dateCharBuffer = new CharBuffer();
private int _dateBufferLength;
private long _lastDate;
private final byte []_logDateBuffer = new byte[64];
private final CharBuffer _logDateCharBuffer = new CharBuffer();
private int _logMinutesOffset;
private int _logSecondsOffset;
private int _logDateBufferLength;
private long _lastLogDate;
private boolean _isHeaderWritten;
private String _serverHeader;
private long _contentLengthOut;
private boolean _isClosed;
private ArrayList _cookiesOut;
private boolean _isKeepalive;
private RequestFacade _request;
private boolean _isChunkedIn;
/**
* Create a new Request. Because the actual initialization occurs with
* the start() method, this just allocates statics.
*
* @param server the parent server
*/
protected RequestHttpBase(ProtocolHttp protocolHttp)
{
Objects.requireNonNull(protocolHttp);
_protocolHttp = protocolHttp;
//_rawRead = conn.getReadStream();
//_readStream = new ReadStream();
//_readStream.setReuseBuffer(true);
//_bufferedReader = new BufferedReaderAdapter(_readStream);
for (int i = 0; i < _smallHeaderKeys.length; i++) {
_smallHeaderKeys[i] = new CharSegment();
_smallHeaderValues[i] = new CharSegment();
}
int logSize = 256;
if (getHttpContainer() != null) {
logSize = getHttpContainer().getAccessLogBufferSize();
}
_logBuffer = new LogBuffer(logSize, true);
}
public void init(ConnectionHttp connHttp)
{
Objects.requireNonNull(connHttp);
_conn = connHttp.connTcp();
_connHttp = connHttp;
}
public OutHttpProxy outProxy()
{
return _connHttp.outProxy();
}
public ProtocolHttp protocolHttp()
{
return _protocolHttp;
}
public ConnectionTcp conn()
{
return _conn;
}
public ConnectionHttp connHttp()
{
return _connHttp;
}
public HttpContainer http()
{
if (_protocolHttp != null) {
return _protocolHttp.http();
}
else {
return null;
}
}
/**
* Returns the connection.
*/
public final ConnectionTcp getConnection()
{
return _conn;
}
public final long connectionId()
{
return _conn.id();
}
/**
* returns the dispatch server.
*/
public final InvocationManager getInvocationManager()
{
return http().getInvocationManager();
}
protected final CharBuffer getCharBuffer()
{
return _cb;
}
/**
* Prepare the Request object for a new request.
*
* @param httpBuffer the raw connection stream
*/
protected void initRequest()
{
_hostHeader = null;
_xForwardedHostHeader = null;
_expect100Continue = false;
_cookies.clear();
_contentLengthIn = -1;
_hasReadStream = false;
_readEncoding = null;
//_request = request;
//_requestFacade = getHttp().createFacade(this);
_startTime = -1;
_expireTime = -1;
_isUpgrade = false;
_statusCode = 200;
_statusMessage = "OK";
_headerKeys.clear();
_headerValues.clear();
_footerKeys.clear();
_footerValues.clear();
getOut().start();
_isHeaderWritten = false;
_contentLengthOut = -1;
_isClosed = false;
_serverHeader = null;
_isKeepalive = true;
}
protected RequestFacade request()
{
throw new UnsupportedOperationException();
}
protected RequestFacade next()
{
return null;
}
protected void closeWrite()
{
/*
RequestFacade request = _request;
_request = null;
if (request != null) {
request.onCloseWrite(next());
}
*/
//_state.onCloseWrite(next());
}
public Invocation parseInvocation() throws IOException
{
return null;
}
public boolean readBodyChunk() throws IOException
{
return false;
}
protected void clearRequest()
{
//_requestFacade = null;
}
/**
* Returns true if a request has been set
*/
/*
public boolean hasRequest()
{
//return _requestFacade != null;
return false;
}
*/
protected final byte []getSmallUriBuffer()
{
return _smallUriBuffer;
}
protected final char []getSmallHeaderBuffer()
{
return _smallHeaderBuffer;
}
protected final CharSegment []getSmallHeaderKeys()
{
return _smallHeaderKeys;
}
protected final CharSegment []getSmallHeaderValues()
{
return _smallHeaderValues;
}
/**
* Returns the http buffer store
*/
protected final HttpBufferStore getHttpBufferStore()
{
return _largeHttpBuffer;
}
protected final HttpBufferStore allocateHttpBufferStore()
{
if (_largeHttpBuffer != null) {
throw new IllegalStateException();
}
_largeHttpBuffer = http().allocateHttpBuffer();
return _largeHttpBuffer;
}
/*
public WriteStream getRawWrite()
{
return _conn.getWriteStream();
}
*/
public abstract byte []getUriBuffer();
public abstract int getUriLength();
/**
* Returns true if client disconnects should be ignored.
*/
public boolean isIgnoreClientDisconnect()
{
// server/183c
return http().isIgnoreClientDisconnect();
}
protected HttpContainer getHttpContainer()
{
return http();
}
/**
* Returns true if the client has disconnected
*/
public boolean isConnectionClosed()
{
if (_conn != null)
return _conn.isClosed();
else
return false;
}
/**
* Called when the client has disconnected
*/
public void clientDisconnect()
{
try {
OutResponseBase responseStream = _responseStream;
if (responseStream != null) {
responseStream.close();
}
} catch (Exception e) {
log.log(Level.FINER, e.toString(), e);
}
ConnectionTcp conn = _conn;
if (conn != null) {
conn.clientDisconnect();
}
killKeepalive("client disconnect");
}
protected CharSegment getHostHeader()
{
return _hostHeader;
}
protected CharSegment getForwardedHostHeader()
{
return _xForwardedHostHeader;
}
/**
* Returns the local server name.
*/
public String getServerName()
{
String host = _conn.getVirtualHost();
/*
if (host == null && _invocation != null)
host = _invocation.getHostName();
*/
CharSequence rawHost;
if (host == null && (rawHost = getHost()) != null) {
if (rawHost instanceof CharSegment) {
CharSegment cb = (CharSegment) rawHost;
char []buffer = cb.buffer();
int offset = cb.offset();
int length = cb.length();
for (int i = length - 1; i >= 0; i--) {
char ch = buffer[i + offset];
if ('A' <= ch && ch <= 'Z') {
buffer[i + offset] = (char) (ch + 'a' - 'A');
}
}
host = new String(buffer, offset, length);
}
else
return rawHost.toString().toLowerCase(Locale.ENGLISH);
}
if (host == null) {
InetAddress addr = _conn.getLocalAddress();
return addr.getHostName();
}
int p1 = host.lastIndexOf('/');
if (p1 < 0) {
p1 = 0;
}
int ipv6 = host.lastIndexOf(']');
int p = host.lastIndexOf(':');
if (p >= 0 && p1 < p && ! (ipv6 > 0 && p < ipv6)) {
return host.substring(p1, p);
}
else {
return host;
}
}
protected CharSequence getHost()
{
return null;
}
/**
* Returns the server's port.
*/
public int getServerPort()
{
String host = _conn.getVirtualHost();
CharSequence rawHost;
if (host == null && (rawHost = getHost()) != null) {
int length = rawHost.length();
int i;
for (i = length - 1; i >= 0; i--) {
if (rawHost.charAt(i) == ':') {
int port = 0;
for (i++; i < length; i++) {
char ch = rawHost.charAt(i);
if ('0' <= ch && ch <= '9') {
port = 10 * port + ch - '0';
}
}
return port;
}
}
// server/0521 vs server/052o
// because of proxies, need to use the host header,
// not the actual port
return isSecure() ? 443 : 80;
}
if (host == null)
return _conn.getLocalPort();
int p1 = host.lastIndexOf(':');
if (p1 < 0)
return isSecure() ? 443 : 80;
else {
int length = host.length();
int port = 0;
for (int i = p1 + 1; i < length; i++) {
char ch = host.charAt(i);
if ('0' <= ch && ch <= '9') {
port = 10 * port + ch - '0';
}
}
return port;
}
}
/**
* Returns the local port.
*/
public int getLocalPort()
{
return _conn.getLocalPort();
}
/**
* Returns the server's address.
*/
public String getLocalHost()
{
return _conn.getLocalHost();
}
public String getRemoteAddr()
{
return _conn.ip();
}
public int printRemoteAddr(byte []buffer, int offset)
throws IOException
{
int len = _conn.getRemoteAddress(buffer, offset, buffer.length - offset);
return offset + len;
}
public String remoteHost()
{
return _conn.ip();
}
/**
* Returns the local port.
*/
public int getRemotePort()
{
return _conn.getRemotePort();
}
/**
* Returns the request's scheme.
*/
public String getScheme()
{
return isSecure() ? "https" : "http";
}
abstract public String getProtocol();
abstract public String getMethod();
/**
* Returns the named header.
*
* @param key the header key
*/
abstract public String getHeader(String key);
protected boolean isUpgrade()
{
return _isUpgrade;
}
/**
* Returns the number of headers.
*/
public int getHeaderSize()
{
return -1;
}
/**
* Returns the header key
*/
public CharSegment getHeaderKey(int index)
{
throw new UnsupportedOperationException();
}
/**
* Returns the header value
*/
public CharSegment getHeaderValue(int index)
{
throw new UnsupportedOperationException();
}
/**
* Fills the result with the header values as
* CharSegment values. Most implementations will
* implement this directly.
*
* @param name the header name
*/
public CharSegment getHeaderBuffer(String name)
{
String value = getHeader(name);
if (value != null)
return new CharBuffer(value);
else
return null;
}
/**
* Enumerates the header keys
*/
//abstract public Enumeration getHeaderNames();
/**
* Sets the header. setHeader is used for
* Resin's caching to simulate If-None-Match.
*/
public void setHeader(String key, String value)
{
}
/**
* Adds the header, checking for known values.
*/
protected boolean addHeaderInt(char []keyBuf, int keyOff, int keyLen,
CharSegment value)
{
if (keyLen < 4)
return true;
int key1 = keyBuf[keyOff] | 0x20 | (keyLen << 8);
switch (key1) {
case CONNECTION_KEY:
if (match(keyBuf, keyOff, keyLen, CONNECTION)) {
char []valueBuffer = value.buffer();
int valueOffset = value.offset();
int valueLength = value.length();
boolean isKeepalive = false;
switch (valueBuffer[valueOffset]) {
case 'k':
case 'K':
if (match(valueBuffer, valueOffset, valueLength, KEEPALIVE)) {
isKeepalive = true;
}
break;
case 'u':
case 'U':
if (match(valueBuffer, valueOffset, UPGRADE.length, UPGRADE)) {
_isUpgrade = true;
}
break;
}
_isKeepalive = isKeepalive;
return true;
}
case COOKIE_KEY:
if (match(keyBuf, keyOff, keyLen, COOKIE)) {
fillCookie(_cookies, value);
}
return true;
case CONTENT_LENGTH_KEY:
if (match(keyBuf, keyOff, keyLen, CONTENT_LENGTH)) {
contentLengthIn(value);
}
return true;
case EXPECT_KEY:
if (match(keyBuf, keyOff, keyLen, EXPECT)) {
if (match(value.buffer(), value.offset(), value.length(),
CONTINUE_100)) {
_expect100Continue = true;
return false;
}
}
return true;
case HOST_KEY:
if (match(keyBuf, keyOff, keyLen, HOST)) {
_hostHeader = value;
}
return true;
case TRANSFER_ENCODING_KEY:
if (match(keyBuf, keyOff, keyLen, TRANSFER_ENCODING)) {
_isChunkedIn = true;
}
return true;
case X_FORWARDED_HOST_KEY:
if (match(keyBuf, keyOff, keyLen, X_FORWARDED_HOST)) {
_xForwardedHostHeader = value;
}
return true;
default:
return true;
}
}
protected void contentLengthIn(CharSegment value)
{
long contentLength = 0;
int ch;
int i = 0;
int length = value.length();
for (;
i < length && (ch = value.charAt(i)) >= '0' && ch <= '9';
i++) {
contentLength = 10 * contentLength + ch - '0';
}
if (i > 0)
_contentLengthIn = contentLength;
}
/**
* Called for a connection: close
*/
protected void handleConnectionClose()
{
ConnectionTcp conn = _conn;
if (conn != null) {
killKeepalive("client Connection: close");
}
}
/**
* Matches case insensitively, with the second normalized to lower case.
*/
private boolean match(char []a, int aOff, int aLength, char []b)
{
int bLength = b.length;
if (aLength != bLength)
return false;
for (int i = aLength - 1; i >= 0; i--) {
char chA = a[aOff + i];
char chB = b[i];
if (chA != chB && chA + 'a' - 'A' != chB) {
return false;
}
}
return true;
}
/**
* Returns an enumeration of the headers for the named attribute.
*
* @param name the header name
*/
public Enumeration getHeaders(String name)
{
String value = getHeader(name);
if (value == null) {
return Collections.emptyEnumeration();
}
ArrayList list = new ArrayList();
list.add(value);
return Collections.enumeration(list);
}
/**
* Fills the result with a list of the header values as
* CharSegment values. Most implementations will
* implement this directly.
*
* @param name the header name
* @param resultList the resulting buffer
*/
public void getHeaderBuffers(String name, ArrayList resultList)
{
String value = getHeader(name);
if (value != null)
resultList.add(new CharBuffer(value));
}
/**
* Returns the named header, converted to an integer.
*
* @param key the header key.
*
* @return the value of the header as an integer.
*/
public int getIntHeader(String key)
{
CharSegment value = getHeaderBuffer(key);
if (value == null)
return -1;
int len = value.length();
if (len == 0)
throw new NumberFormatException(value.toString());
int iValue = 0;
int i = 0;
int ch = value.charAt(i);
int sign = 1;
if (ch == '+') {
if (i + 1 < len)
ch = value.charAt(++i);
else
throw new NumberFormatException(value.toString());
} else if (ch == '-') {
sign = -1;
if (i + 1 < len)
ch = value.charAt(++i);
else
throw new NumberFormatException(value.toString());
}
for (; i < len && (ch = value.charAt(i)) >= '0' && ch <= '9'; i++)
iValue = 10 * iValue + ch - '0';
if (i < len)
throw new NumberFormatException(value.toString());
return sign * iValue;
}
/**
* Returns the content length of a post.
*/
public long contentLength()
{
return _contentLengthIn;
}
/**
* Returns the content-type of a post.
*/
public String contentType()
{
return getHeader("Content-Type");
}
/**
* Returns the content-length of a post.
*/
public CharSegment getContentTypeBuffer()
{
return getHeaderBuffer("Content-Type");
}
/**
* Returns the character encoding of a post.
*/
public String encoding()
{
if (_readEncoding != null)
return _readEncoding;
CharSegment value = getHeaderBuffer("Content-Type");
if (value == null)
return null;
int i = value.indexOf("charset");
if (i < 0)
return null;
int len = value.length();
for (i += 7; i < len && Character.isWhitespace(value.charAt(i)); i++) {
}
if (i >= len || value.charAt(i) != '=')
return null;
for (i++; i < len && Character.isWhitespace(value.charAt(i)); i++) {
}
if (i >= len)
return null;
char end = value.charAt(i);
if (end == '"') {
int tail;
for (tail = ++i; tail < len; tail++) {
if (value.charAt(tail) == end)
break;
}
_readEncoding = Encoding.getMimeName(value.substring(i, tail));
return _readEncoding;
}
int tail;
for (tail = i; tail < len; tail++) {
if (Character.isWhitespace(value.charAt(tail))
|| value.charAt(tail) == ';')
break;
}
_readEncoding = Encoding.getMimeName(value.substring(i, tail));
return _readEncoding;
}
/**
* Sets the character encoding of a post.
*/
/*
public void setCharacterEncoding(String encoding)
throws UnsupportedEncodingException
{
// server/122k (tck)
if (_hasReadStream)
return;
_readEncoding = encoding;
try {
// server/122d (tck)
//if (_hasReadStream)
_readStream.setEncoding(_readEncoding);
} catch (UnsupportedEncodingException e) {
throw e;
} catch (java.nio.charset.UnsupportedCharsetException e) {
throw new UnsupportedEncodingException(e.getMessage());
}
}
*/
/**
* Returns the cookies from the browser
*/
public CookieWeb []getCookies()
{
return fillCookies();
/*
// The page varies depending on the presense of any cookies
setVaryCookie(null);
if (_cookiesIn == null)
fillCookies();
// If any cookies actually exist, the page is not anonymous
if (_cookiesIn != null && _cookiesIn.length > 0)
setHasCookie();
if (_cookiesIn == null || _cookiesIn.length == 0)
return null;
else
return _cookiesIn;
*/
}
/**
* Parses cookie information from the cookie headers.
*/
CookieWeb []fillCookies()
{
int size = _cookies.size();
if (size > 0) {
CookieWeb []cookiesIn = new WebCookie[size];
for (int i = size - 1; i >= 0; i--) {
cookiesIn[i] = _cookies.get(i);
}
return cookiesIn;
}
else {
return NULL_COOKIES;
}
}
protected void addCookie(String cookie)
{
_cb.clear();
_cb.append(cookie);
fillCookie(_cookies, _cb);
}
/**
* Parses a single cookie
*
* @param cookies the array of cookies read
* @param rawCookie the input for the cookie
*/
private void fillCookie(ArrayList cookies, CharSegment rawCookie)
{
char []buf = rawCookie.buffer();
int j = rawCookie.offset();
int end = j + rawCookie.length();
int version = 0;
WebCookie cookie = null;
while (j < end) {
char ch = 0;
CharBuffer cbName = _cbName;
CharBuffer cbValue = _cbValue;
cbName.clear();
cbValue.clear();
for (;
j < end && ((ch = buf[j]) == ' ' || ch == ';' || ch ==',');
j++) {
}
if (end <= j)
break;
boolean isSpecial = false;
if (buf[j] == '$') {
isSpecial = true;
j++;
}
for (; j < end; j++) {
ch = buf[j];
if (ch < 128 && TOKEN[ch])
cbName.append(ch);
else
break;
}
for (; j < end && (ch = buf[j]) == ' '; j++) {
}
if (end <= j)
break;
else if (ch == ';' || ch == ',') {
try {
cookie = new WebCookie(cbName.toString(), "");
cookie.setVersion(version);
_cookies.add(cookie);
// some clients can send bogus cookies
} catch (Exception e) {
log.log(Level.FINE, e.toString(), e);
}
continue;
}
else if (ch != '=') {
for (; j < end && (ch = buf[j]) != ';'; j++) {
}
continue;
}
j++;
for (; j < end && (ch = buf[j]) == ' '; j++) {
}
if (ch == '"') {
for (j++; j < end; j++) {
ch = buf[j];
if (ch == '"')
break;
cbValue.append(ch);
}
j++;
}
else {
int head = j;
int tail = j;
for (; j < end; j++) {
ch = buf[j];
if (ch < 128 && VALUE[ch]) {
cbValue.append(ch);
tail = j + 1;
}
else if (ch == ' ') {
cbValue.append(ch);
// server/01ed
}
else {
break;
}
}
cbValue.length(tail - head);
}
if (! isSpecial) {
if (cbName.length() == 0)
log.warning("bad cookie: " + rawCookie);
else {
cookie = new WebCookie(toName(cbName), cbValue.toString());
cookie.setVersion(version);
_cookies.add(cookie);
}
}
else if (cookie == null) {
if (cbName.matchesIgnoreCase("Version"))
version = cbValue.charAt(0) - '0';
}
else if (cbName.matchesIgnoreCase("Version"))
cookie.setVersion(cbValue.charAt(0) - '0');
else if (cbName.matchesIgnoreCase("Domain"))
cookie.setDomain(cbValue.toString());
else if (cbName.matchesIgnoreCase("Path"))
cookie.setPath(cbValue.toString());
}
}
private String toName(CharBuffer cb)
{
String value = _nameCache.get(cb);
if (value == null) {
value = cb.toString();
cb = new CharBuffer(value);
_nameCache.put(cb, value);
}
return value;
}
/**
* For SSL connections, use the SSL identifier.
*/
public String findSessionIdFromConnection()
{
return null;
}
/**
* Returns true if the transport is secure.
*/
public boolean isTransportSecure()
{
return _conn.isSecure();
}
protected void initAttributes(RequestFacade facade)
{
}
//
// security
//
/**
* Returns true if the request is secure.
*/
public boolean isSecure()
{
return _conn.isSecure();
}
/**
* Returns key-size
*/
/*
public int secureKeySize()
{
return _conn.keySize();
}
*/
//
// internal methods
//
/**
* Returns the date for the current request.
*/
public final long getStartTime()
{
return _startTime;
}
/**
* Returns the log buffer.
*/
/*
public final byte []getLogBuffer()
{
return _httpBuffer.getLogBuffer();
}
*/
public final void onAttachThread()
{
}
public final void onDetachThread()
{
HttpBufferStore httpBuffer = _largeHttpBuffer;
_largeHttpBuffer = null;
if (httpBuffer != null) {
http().freeHttpBuffer(httpBuffer);
}
}
protected Invocation getInvocation(CharSequence host,
byte []uri,
int uriLength)
throws IOException
{
_invocationKey.init(isSecure(),
host, getServerPort(),
uri, uriLength);
InvocationManager> server = http().getInvocationManager();
Invocation invocation = server.getInvocation(_invocationKey);
if (invocation != null) {
//return invocation.getRequestInvocation(_requestFacade);
return invocation;
}
invocation = server.createInvocation();
invocation.setSecure(isSecure());
if (host != null) {
String hostName = host.toString().toLowerCase(Locale.ENGLISH);
invocation.setHost(hostName);
invocation.setPort(getServerPort());
// Default host name if the host doesn't have a canonical
// name
int p = hostName.lastIndexOf(':');
int q = hostName.lastIndexOf(']');
if (p > 0 && q < p) {
invocation.setHostName(hostName.substring(0, p));
}
else {
invocation.setHostName(hostName);
}
}
return buildInvocation(invocation, uri, uriLength);
}
protected I buildInvocation(I invocation,
byte []uri,
int uriLength)
throws IOException
{
HttpContainer http = http();
InvocationManager manager
= (InvocationManager) http.getInvocationManager();
InvocationDecoder decoder = manager.getInvocationDecoder();
decoder.splitQueryAndUnescape(invocation, uri, uriLength);
/*
if (httpSystem.isModified()) {
httpSystem.logModified(log);
_requestFacade.setInvocation(invocation);
invocation.setWebApp(httpSystem.getErrorWebApp());
HttpServletResponse res = _responseFacade;
res.sendError(HttpServletResponse.SC_SERVICE_UNAVAILABLE);
httpSystem.restart();
return null;
}
*/
invocation = manager.buildInvocation(_invocationKey.clone(), invocation);
//return invocation.getRequestInvocation(_requestFacade);
return invocation;
}
/**
* Handles a timeout.
*/
public void onTimeout()
{
}
/**
* Starts duplex mode.
*/
public void startDuplex(ConnectionProtocol request)
{
throw new UnsupportedOperationException(getClass().getName());
}
protected void sendRequestError(Throwable e)
throws IOException
{
killKeepalive("request error: " + e);
//getHttp().sendRequestError(e, request());
if (true) throw new UnsupportedOperationException();
}
/**
* Kills the keepalive.
*/
public void killKeepalive(String reason)
{
ConnectionTcp conn = _conn;
_isKeepalive = false;
/* XXX:
if (conn != null) {
conn.killKeepalive(reason);
}
*/
}
/**
* Returns true if the keepalive is active.
*/
public boolean isKeepalive()
{
//ConnectionTcp conn = _conn;
// return conn != null && conn.isKeepaliveAllocated();
return _isKeepalive;
}
public boolean isSuspend()
{
// return _conn != null && (_conn.isCometActive() || _conn.isDuplex());
return false;
}
public boolean isAsync()
{
return isSuspend();
}
public boolean isDuplex()
{
// return _conn != null && _conn.isDuplex();
return false;
}
/*
protected HashMapImpl getForm()
{
_form.clear();
return _form;
}
protected Form getFormParser()
{
return _formParser;
}
*/
/**
* Restarts the server.
*/
/*
protected void restartServer()
{
}
*/
/**
* Prepare the Request object for a new request.
*
*/
/*
protected void startInvocation()
throws IOException
{
_startTime = CurrentTime.getExactTime();
ConnectionTcp tcpConn = _conn;
if (tcpConn != null) {
long requestTimeout = tcpConn.port().getRequestTimeout();
if (requestTimeout > 0)
_expireTime = _startTime + requestTimeout;
else
_expireTime = Long.MAX_VALUE / 2;
}
}
*/
public void onCloseConnection()
{
try {
finishRequest();
} catch (Exception e) {
log.log(Level.FINE, e.toString(), e);
}
HttpBufferStore httpBuffer = _largeHttpBuffer;
_largeHttpBuffer = null;
if (httpBuffer != null) {
http().freeHttpBuffer(httpBuffer);
}
}
/**
* Cleans up at the end of the request
*/
private void finishRequest()
throws IOException
{
try {
cleanup();
} catch (Exception e) {
log.log(Level.WARNING, e.toString(), e);
} finally {
//_requestFacade = null;
}
}
public void cleanup()
{
_cookies.clear();
}
/**
* Called by server shutdown to kill any active threads
*/
public void shutdown()
{
}
//
// output
//
/**
* Returns true for closed requests.
*/
public boolean isClosed()
{
return _isClosed;
}
abstract protected OutResponseBase createOut();
/**
* Gets the response stream.
*/
public final OutResponseBase getOut()
{
OutResponseBase stream = _responseStream;
if (stream == null) {
stream = createOut();
_responseStream = stream;
}
return stream;
}
public final void freeResponseStream()
{
OutResponseBase responseStream = _responseStream;
_responseStream = null;
//_responseOutputStream.init(null);
//_responsePrintWriter.init(null);
if (responseStream != null) {
freeResponseStream(responseStream);
}
}
protected void freeResponseStream(OutResponseBase stream)
{
}
/**
* For a HEAD request, the response stream should write no data.
*/
protected void setHead()
{
getOut().toHead();
}
/**
* For a HEAD request, the response stream should write no data.
*/
protected final boolean isHead()
{
return getOut().isHead();
}
//
// status
//
public void status(int code, String message)
{
if (code < 100 || code >= 600) {
throw new IllegalArgumentException(String.valueOf(code));
}
Objects.requireNonNull(message);
_statusCode = code;
_statusMessage = message;
}
protected int status()
{
return _statusCode;
}
protected String statusMessage()
{
return _statusMessage;
}
//
// headers
//
/**
* Returns true if the response already contains the named header.
*
* @param name name of the header to test.
*/
public boolean containsHeaderOut(String name)
{
ArrayList headerKeys = _headerKeys;
int size = headerKeys.size();
for (int i = 0; i < size; i++) {
String oldKey = headerKeys.get(i);
if (oldKey.equalsIgnoreCase(name)) {
return true;
}
}
if (name.equalsIgnoreCase("content-type")) {
//return request().getContentType() != null;
throw new UnsupportedOperationException();
}
if (name.equalsIgnoreCase("content-length")) {
return _contentLengthOut >= 0;
}
return false;
}
/**
* Returns the value of an already set output header.
*
* @param name name of the header to get.
*/
public String headerOut(String name)
{
ArrayList keys = _headerKeys;
int headerSize = keys.size();
for (int i = 0; i < headerSize; i++) {
String oldKey = keys.get(i);
if (oldKey.equalsIgnoreCase(name)) {
return (String) _headerValues.get(i);
}
}
/*
if (name.equalsIgnoreCase("content-type")) {
throw new UnsupportedOperationException();
//return request().getContentType();
}
*/
if (name.equalsIgnoreCase("content-length")) {
return _contentLengthOut >= 0 ? String.valueOf(_contentLengthOut) : null;
}
return null;
}
/**
* Sets a header, replacing an already-existing header.
*
* @param key the header key to set.
* @param value the header value to set.
*/
public void setHeaderOut(String key, String value)
{
Objects.requireNonNull(value);
if (isOutCommitted()) {
return;
}
// #5824, server/1m15
/*
if (value == null)
throw new NullPointerException();
*/
if (setHeaderOutSpecial(key, value)) {
return;
}
// server/05e8 (tck)
// XXX: server/13w0 for _isHeaderWritten because the Expires in caching
// occurs after the output fills (committed), which contradicts the tck
// requirements
/*
if (isOutCommitted() && ! _isHeaderWritten) {
return;
}
*/
setHeaderOutImpl(key, value);
/*
if (value != null) {
setHeaderOutImpl(key, value);
}
else {
removeHeader(key);
}
*/
}
/**
* Sets a header, replacing an already-existing header.
*
* @param key the header key to set.
* @param value the header value to set.
*/
protected void setHeaderOutImpl(String key, String value)
{
int i = 0;
boolean hasHeader = false;
ArrayList keys = _headerKeys;
ArrayList values = _headerValues;
for (i = keys.size() - 1; i >= 0; i--) {
String oldKey = keys.get(i);
if (oldKey.equalsIgnoreCase(key)) {
if (hasHeader) {
keys.remove(i);
values.remove(i);
}
else {
hasHeader = true;
values.set(i, value);
}
}
}
if (! hasHeader) {
keys.add(key);
values.add(value);
}
}
/**
* Adds a new header. If an old header with that name exists,
* both headers are output.
*
* @param key the header key.
* @param value the header value.
*/
public void addHeaderOut(String key, String value)
{
// server/05e8 (tck)
if (isOutCommitted()) {
return;
}
addHeaderOutImpl(key, value);
}
/**
* Adds a new header. If an old header with that name exists,
* both headers are output.
*
* @param key the header key.
* @param value the header value.
*/
public void addHeaderOutImpl(String key, String value)
{
if (setHeaderOutSpecial(key, value)) {
return;
}
ArrayList keys = _headerKeys;
ArrayList values = _headerValues;
int size = keys.size();
// webapp/1k32
for (int i = 0; i < size; i++) {
if (keys.get(i).equals(key) && values.get(i).equals(value)) {
return;
}
}
keys.add(key);
values.add(value);
}
protected static ContentType parseContentType(String contentType)
{
ContentType item = _contentTypeMap.get(contentType);
if (item == null) {
item = new ContentType(contentType);
_contentTypeMap.put(contentType, item);
}
return item;
}
/**
* Special processing for a special value.
*/
private boolean setHeaderOutSpecial(String key, String value)
{
int length = key.length();
if (length == 0) {
return false;
}
int ch = key.charAt(0);
if ('A' <= ch && ch <= 'Z') {
ch += 'a' - 'A';
}
int code = (length << 8) + ch;
/*
if (256 <= length)
return false;
key.getChars(0, length, _headerBuffer, 0);
*/
switch (code) {
case 0x0d00 + 'c':
if (CACHE_CONTROL.matchesIgnoreCase(key)) {
// server/13d9, server/13dg
if (value.startsWith("max-age")) {
}
else if (value.startsWith("s-maxage")) {
}
else if (value.equals("x-anonymous")) {
}
else {
//request().setCacheControl(true);
if (true) throw new UnsupportedOperationException();
}
}
return false;
case 0x0a00 + 'c':
if (CONNECTION_CB.matchesIgnoreCase(key)) {
if ("close".equalsIgnoreCase(value))
killKeepalive("client connection: close");
return true;
}
else {
return false;
}
/*
case 0x0c00 + 'c':
if (CONTENT_TYPE.matchesIgnoreCase(key)) {
//request().setContentType(value);
if (true) throw new UnsupportedOperationException();
return true;
}
else {
return false;
}
*/
case 0x0e00 + 'c':
if (CONTENT_LENGTH_CB.matchesIgnoreCase(key)) {
// server/05a8
// php/164v
_contentLengthOut = parseLong(value);
return true;
}
else {
return false;
}
case 0x0400 + 'd':
if (DATE.matchesIgnoreCase(key)) {
return true;
}
else {
return false;
}
case 0x0600 + 's':
if (SERVER.matchesIgnoreCase(key)) {
_serverHeader = value;
return true;
}
else {
return false;
}
default:
return false;
}
}
private static long parseLong(String string)
{
int length = string.length();
int i;
int ch = 0;
for (i = 0;
i < length && Character.isWhitespace((ch = string.charAt(i)));
i++) {
}
int sign = 1;
long value = 0;
if (ch == '-') {
sign = -1;
if (i < length) {
ch = string.charAt(i++);
}
}
else if (ch == '+') {
if (i < length) {
ch = string.charAt(i++);
}
}
if (! ('0' <= ch && ch <= '9')) {
throw new IllegalArgumentException(L.l("'{0}' is an invalid content-length",
string));
}
for (;
i < length && '0' <= (ch = string.charAt(i)) && ch <= '9';
i++) {
value = 10 * value + ch - '0';
}
return sign * value;
}
public void removeHeader(String key)
{
if (isOutCommitted()) {
return;
}
ArrayList keys = _headerKeys;
ArrayList values = _headerValues;
for (int i = keys.size() - 1; i >= 0; i--) {
String oldKey = keys.get(i);
if (oldKey.equalsIgnoreCase(key)) {
keys.remove(i);
values.remove(i);
return;
}
}
}
public ArrayList headerKeysOut()
{
return _headerKeys;
}
public ArrayList headerValuesOut()
{
return _headerValues;
}
public Collection headersOut(String name)
{
ArrayList headers = new ArrayList();
for (int i = 0; i < _headerKeys.size(); i++) {
String key = _headerKeys.get(i);
if (key.equals(name))
headers.add(_headerValues.get(i));
}
return headers;
}
public Collection headerNamesOut()
{
return new HashSet(_headerKeys);
}
public ArrayList footerKeysOut()
{
return _footerKeys;
}
public ArrayList footerValuesOut()
{
return _footerValues;
}
/**
* Sets the content length of the result. In general, Resin will handle
* the content length, but for things like long downloads adding the
* length will give a valuable hint to the browser.
*
* @param length the length of the content.
*/
public void contentLengthOut(long length)
{
_contentLengthOut = length;
}
/**
* Returns the value of the content-length header.
*/
public final long contentLengthOut()
{
return _contentLengthOut;
}
public String serverHeader()
{
return _serverHeader;
}
/**
* Sets a footer, replacing an already-existing footer
*
* @param key the header key to set.
* @param value the header value to set.
*/
public void setFooter(String key, String value)
{
Objects.requireNonNull(value);
int i = 0;
boolean hasFooter = false;
for (i = _footerKeys.size() - 1; i >= 0; i--) {
String oldKey = _footerKeys.get(i);
if (oldKey.equalsIgnoreCase(key)) {
if (hasFooter) {
_footerKeys.remove(i);
_footerValues.remove(i);
}
else {
hasFooter = true;
_footerValues.set(i, value);
}
}
}
if (! hasFooter) {
_footerKeys.add(key);
_footerValues.add(value);
}
}
/**
* Adds a new footer. If an old footer with that name exists,
* both footers are output.
*
* @param key the footer key.
* @param value the footer value.
*/
public void addFooter(String key, String value)
{
if (setHeaderOutSpecial(key, value)) {
return;
}
_footerKeys.add(key);
_footerValues.add(value);
}
protected boolean hasFooter()
{
return _footerKeys.size() > 0;
}
public void cookie(CookieWeb cookie)
{
if (_cookiesOut == null) {
_cookiesOut = new ArrayList<>();
}
_cookiesOut.add(cookie);
}
protected ArrayList cookiesOut()
{
return _cookiesOut;
}
/**
* Returns true if some data has been sent to the browser.
*/
public final boolean isOutCommitted()
{
OutResponseBase stream = getOut();
if (stream.isCommitted()) {
return true;
}
// server/05a7
if (_contentLengthOut > 0 && _contentLengthOut <= stream.getContentLength()) {
return true;
}
return false;
}
protected void resetOut()
{
if (isOutCommitted()) {
return;
}
_headerKeys.clear();
_headerValues.clear();
_contentLengthOut = -1;
}
public void upgrade()
{
}
/**
* Returns the number of bytes sent to the output.
*/
public long contentLengthSent()
{
OutResponseBase stream = _responseStream;
// stream can be null for duplex (websocket)
if (stream != null) {
return stream.getContentLength();
}
else {
return Math.max(_contentLengthOut, 0);
}
}
/**
* Returns true if the headers have been written.
*/
public boolean isHeaderWritten()
{
return _isHeaderWritten;
}
/**
* Returns true if the headers have been written.
*/
public void setHeaderWritten(boolean isWritten)
{
_isHeaderWritten = isWritten;
}
//
// http writer methods
//
/**
* Writes the continue
*/
final void writeContinue()
throws IOException
{
if (! isHeaderWritten()) {
// writeContinueInt(_rawWrite);
// _rawWrite.flush();
writeContinueInt();
}
}
/**
* Writes the continue from the writer thread.
*/
protected void writeContinueInt()
throws IOException
{
}
/*
@Override
public void writeFirst(OutHttpProxy out,
TempBuffer buffer,
long length,
boolean isEnd)
{
System.out.println("FIRST: " + this);
if (! isEnd) {
buffer.freeSelf();
}
}
@Override
public void writeNext(OutHttpProxy out,
TempBuffer buffer,
boolean isEnd)
{
System.out.println("NEXT: " + this);
if (! isEnd) {
buffer.freeSelf();
}
}
*/
@Override
public void disconnect(WriteBuffer out)
{
try {
out.close();
} catch (IOException e) {
e.printStackTrace();
}
}
protected void fillHeaders()
{
/*
RequestFacade res = request();
addSensorCount(res.getStatus());
res.fillHeaders();
*/
}
private void addSensorCount(int statusCode)
{
int majorCode = statusCode / 100;
switch (majorCode) {
case 2:
_status2xxSensor.start();
switch (statusCode) {
case 200:
_status200Sensor.start();
break;
default:
_status2xxSensor.start();
break;
}
break;
case 3:
switch (statusCode) {
case 304:
_status304Sensor.start();
break;
default:
_status3xxSensor.start();
break;
}
break;
case 4:
switch (statusCode) {
case 400:
_status400Sensor.start();
_status4xxSensor.start();
break;
case 404:
_status404Sensor.start();
break;
default:
_status4xxSensor.start();
break;
}
break;
case 5:
/*
if (webApp != null)
webApp.addStatus500();
*/
_status5xxSensor.start();
switch (statusCode) {
case 500:
_status500Sensor.start();
break;
case 503:
_status503Sensor.start();
break;
default:
break;
}
break;
default:
_statusXxxSensor.start();
break;
}
}
/*
abstract protected void writeHeaders(long length)
throws IOException;
*/
public void writePending()
{
}
public final LogBuffer getLogBuffer()
{
return _logBuffer;
}
public final byte []fillDateBuffer(long now)
{
if (_lastDate / 1000 != now / 1000) {
fillDate(now);
}
return _dateBuffer;
}
public final int getDateBufferLength()
{
return _dateBufferLength;
}
public final int getRawDateBufferOffset()
{
return 8; // "\r\nDate: "
}
public final int getRawDateBufferLength()
{
return 24;
}
private void fillDate(long now)
{
byte []dateBuffer = _dateBuffer;
if (_lastDate / HOUR == now / HOUR) {
int min = (int) (now / 60000 % 60);
int sec = (int) (now / 1000 % 60);
int m2 = '0' + (min / 10);
int m1 = '0' + (min % 10);
int s2 = '0' + (sec / 10);
int s1 = '0' + (sec % 10);
dateBuffer[28] = (byte) m2;
dateBuffer[29] = (byte) m1;
dateBuffer[31] = (byte) s2;
dateBuffer[32] = (byte) s1;
_lastDate = now;
return;
}
Instant instant = ClockCurrent.GMT.instant();
OffsetDateTime time = OffsetDateTime.ofInstant(instant, ZoneOffset.UTC);
_lastDate = instant.toEpochMilli();
CharBuffer dateCharBuffer = _dateCharBuffer;
dateCharBuffer.clear();
dateCharBuffer.append("\r\nDate: ");
//DateTimeFormatter formatter = DateTimeFormatter.RFC_1123_DATE_TIME;
_dateCharBuffer.append(_dateFormatter.format(time));
_dateCharBuffer.append(" GMT");
//calendar.printDate(_dateCharBuffer);
//QDate.freeGmtDate(calendar);
char []cb = dateCharBuffer.buffer();
int len = dateCharBuffer.length();
for (int i = len - 1; i >= 0; i--) {
dateBuffer[i] = (byte) cb[i];
}
dateBuffer[len] = (byte) '\r';
dateBuffer[len + 1] = (byte) '\n';
dateBuffer[len + 2] = (byte) '\r';
dateBuffer[len + 3] = (byte) '\n';
_dateBufferLength = len + 4;
}
public final byte []fillLogDateBuffer(long now,
String timeFormat)
{
if (_lastLogDate / 1000 != now / 1000) {
fillLogDate(now, timeFormat);
}
return _logDateBuffer;
}
public final int getLogDateBufferLength()
{
return _logDateBufferLength;
}
private void fillLogDate(long now,
String timeFormat)
{
byte []logDateBuffer = _logDateBuffer;
if (_lastLogDate / HOUR == now / HOUR) {
int min = (int) (now / 60000 % 60);
int sec = (int) (now / 1000 % 60);
int m2 = '0' + (min / 10);
int m1 = '0' + (min % 10);
int s2 = '0' + (sec / 10);
int s1 = '0' + (sec % 10);
logDateBuffer[_logMinutesOffset + 0] = (byte) m2;
logDateBuffer[_logMinutesOffset + 1] = (byte) m1;
logDateBuffer[_logSecondsOffset + 0] = (byte) s2;
logDateBuffer[_logSecondsOffset + 1] = (byte) s1;
_lastLogDate = now;
return;
}
//QDate localCalendar = QDate.allocateLocalDate();
Instant time = ClockCurrent.GMT.instant();
_lastLogDate = time.toEpochMilli();
//localCalendar.setGMTTime(now);
_logDateCharBuffer.clear();
_logDateCharBuffer.append(_dateFormatter.format(time));
//localCalendar.format(_logDateCharBuffer, timeFormat);
//QDate.freeLocalDate(localCalendar);
_logSecondsOffset = _logDateCharBuffer.lastIndexOf(':') + 1;
_logMinutesOffset = _logSecondsOffset - 3;
char []cb = _logDateCharBuffer.buffer();
int len = _logDateCharBuffer.length();
for (int i = len - 1; i >= 0; i--) {
logDateBuffer[i] = (byte) cb[i];
}
_logDateBufferLength = len;
}
/**
* Closes the request, called from web-app for early close.
*/
public void close()
throws IOException
{
/*
// server/125i
if (! isSuspend()) {
finishInvocation(true);
// finishRequest(true);
}
*/
}
void closeResponse()
{
OutResponseBase outResponse = _responseStream;
if (outResponse != null) {
IoUtil.close(outResponse);
}
}
protected void free()
{
}
public void freeSelf()
{
}
protected String dbgId()
{
return "Tcp[" + _conn.id() + "] ";
}
static {
_headerCodes = new CaseInsensitiveIntMap();
_headerCodes.put("cache-control", HEADER_CACHE_CONTROL);
_headerCodes.put("connection", HEADER_CONNECTION);
_headerCodes.put("content-type", HEADER_CONTENT_TYPE);
_headerCodes.put("content-length", HEADER_CONTENT_LENGTH);
_headerCodes.put("date", HEADER_DATE);
_headerCodes.put("server", HEADER_SERVER);
//_headerCodes = new CaseInsensitiveIntMap();
TOKEN = new boolean[256];
VALUE = new boolean[256];
for (int i = 0; i < 256; i++) {
TOKEN[i] = true;
}
for (int i = 0; i < 32; i++) {
TOKEN[i] = false;
}
for (int i = 127; i < 256; i++) {
TOKEN[i] = false;
}
//TOKEN['('] = false;
//TOKEN[')'] = false;
//TOKEN['<'] = false;
//TOKEN['>'] = false;
//TOKEN['@'] = false;
TOKEN[','] = false;
TOKEN[';'] = false;
//TOKEN[':'] = false;
TOKEN['\\'] = false;
TOKEN['"'] = false;
//TOKEN['/'] = false;
//TOKEN['['] = false;
//TOKEN[']'] = false;
//TOKEN['?'] = false;
TOKEN['='] = false;
//TOKEN['{'] = false;
//TOKEN['}'] = false;
TOKEN[' '] = false;
System.arraycopy(TOKEN, 0, VALUE, 0, TOKEN.length);
VALUE['='] = true;
_dateFormatter = DateTimeFormatter.ofPattern("EEE, dd MMM yyyy hh:mm:ss");
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy