Introducing Java Servlet Container beta.
This commit is contained in:
3502
src/java/nginx/unit/Context.java
Normal file
3502
src/java/nginx/unit/Context.java
Normal file
File diff suppressed because it is too large
Load Diff
8
src/java/nginx/unit/DynamicDispatcherRequest.java
Normal file
8
src/java/nginx/unit/DynamicDispatcherRequest.java
Normal file
@@ -0,0 +1,8 @@
|
||||
package nginx.unit;
|
||||
|
||||
import javax.servlet.DispatcherType;
|
||||
|
||||
public interface DynamicDispatcherRequest
|
||||
{
|
||||
public void setDispatcherType(DispatcherType type);
|
||||
}
|
||||
15
src/java/nginx/unit/DynamicPathRequest.java
Normal file
15
src/java/nginx/unit/DynamicPathRequest.java
Normal file
@@ -0,0 +1,15 @@
|
||||
package nginx.unit;
|
||||
|
||||
public interface DynamicPathRequest
|
||||
extends DynamicDispatcherRequest
|
||||
{
|
||||
public void setServletPath(String servlet_path, String path_info);
|
||||
|
||||
public void setServletPath(String filter_path, String servlet_path, String path_info);
|
||||
|
||||
public void setRequestURI(String uri);
|
||||
|
||||
public void setQueryString(String query);
|
||||
|
||||
public String getFilterPath();
|
||||
}
|
||||
150
src/java/nginx/unit/ForwardRequestWrapper.java
Normal file
150
src/java/nginx/unit/ForwardRequestWrapper.java
Normal file
@@ -0,0 +1,150 @@
|
||||
package nginx.unit;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import javax.servlet.DispatcherType;
|
||||
import javax.servlet.RequestDispatcher;
|
||||
import javax.servlet.ServletRequest;
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
|
||||
import org.eclipse.jetty.util.MultiMap;
|
||||
import org.eclipse.jetty.util.UrlEncoded;
|
||||
|
||||
public class ForwardRequestWrapper implements DynamicPathRequest
|
||||
{
|
||||
private final Request request_;
|
||||
|
||||
private final boolean keep_attrs;
|
||||
|
||||
private final String orig_filter_path;
|
||||
private final String orig_servlet_path;
|
||||
private final String orig_path_info;
|
||||
private final String orig_uri;
|
||||
private final String orig_context_path;
|
||||
private final String orig_query;
|
||||
|
||||
private final DispatcherType orig_dtype;
|
||||
|
||||
private MultiMap<String> orig_parameters;
|
||||
|
||||
public ForwardRequestWrapper(ServletRequest request)
|
||||
{
|
||||
if (request instanceof Request) {
|
||||
request_ = (Request) request;
|
||||
} else {
|
||||
request_ = (Request) request.getAttribute(Request.BARE);
|
||||
}
|
||||
|
||||
keep_attrs = request_.getAttribute(RequestDispatcher.FORWARD_REQUEST_URI) != null;
|
||||
|
||||
orig_dtype = request_.getDispatcherType();
|
||||
|
||||
orig_filter_path = request_.getFilterPath();
|
||||
orig_servlet_path = request_.getServletPath();
|
||||
orig_path_info = request_.getPathInfo();
|
||||
orig_uri = request_.getRequestURI();
|
||||
orig_context_path = request_.getContextPath();
|
||||
orig_query = request_.getQueryString();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setDispatcherType(DispatcherType type)
|
||||
{
|
||||
request_.setDispatcherType(type);
|
||||
|
||||
/*
|
||||
9.4.2 Forwarded Request Parameters
|
||||
...
|
||||
Note that these attributes must always reflect the information in
|
||||
the original request even under the situation that multiple
|
||||
forwards and subsequent includes are called.
|
||||
*/
|
||||
|
||||
if (keep_attrs) {
|
||||
return;
|
||||
}
|
||||
|
||||
/*
|
||||
9.4.2 Forwarded Request Parameters
|
||||
...
|
||||
The values of these attributes must be equal to the return values
|
||||
of the HttpServletRequest methods getRequestURI, getContextPath,
|
||||
getServletPath, getPathInfo, getQueryString respectively, invoked
|
||||
on the request object passed to the first servlet object in the
|
||||
call chain that received the request from the client.
|
||||
*/
|
||||
|
||||
request_.setAttribute_(RequestDispatcher.FORWARD_SERVLET_PATH, orig_servlet_path);
|
||||
request_.setAttribute_(RequestDispatcher.FORWARD_PATH_INFO, orig_path_info);
|
||||
request_.setAttribute_(RequestDispatcher.FORWARD_REQUEST_URI, orig_uri);
|
||||
request_.setAttribute_(RequestDispatcher.FORWARD_CONTEXT_PATH, orig_context_path);
|
||||
request_.setAttribute_(RequestDispatcher.FORWARD_QUERY_STRING, orig_query);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setServletPath(String servlet_path, String path_info)
|
||||
{
|
||||
request_.setServletPath(servlet_path, path_info);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setServletPath(String filter_path, String servlet_path, String path_info)
|
||||
{
|
||||
request_.setServletPath(filter_path, servlet_path, path_info);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setRequestURI(String uri)
|
||||
{
|
||||
request_.setRequestURI(uri);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setQueryString(String query)
|
||||
{
|
||||
if (query != null) {
|
||||
orig_parameters = request_.getParameters();
|
||||
|
||||
MultiMap<String> parameters = new MultiMap<>();
|
||||
UrlEncoded.decodeUtf8To(query, parameters);
|
||||
|
||||
for (Map.Entry<String, List<String>> e: orig_parameters.entrySet()) {
|
||||
parameters.addValues(e.getKey(), e.getValue());
|
||||
}
|
||||
|
||||
request_.setParameters(parameters);
|
||||
|
||||
request_.setQueryString(query);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getFilterPath()
|
||||
{
|
||||
return request_.getFilterPath();
|
||||
}
|
||||
|
||||
public void close()
|
||||
{
|
||||
request_.setDispatcherType(orig_dtype);
|
||||
|
||||
request_.setRequestURI(orig_uri);
|
||||
request_.setServletPath(orig_filter_path, orig_servlet_path, orig_path_info);
|
||||
request_.setQueryString(orig_query);
|
||||
|
||||
if (orig_parameters != null) {
|
||||
request_.setParameters(orig_parameters);
|
||||
}
|
||||
|
||||
if (keep_attrs) {
|
||||
return;
|
||||
}
|
||||
|
||||
request_.setAttribute_(RequestDispatcher.FORWARD_SERVLET_PATH, null);
|
||||
request_.setAttribute_(RequestDispatcher.FORWARD_PATH_INFO, null);
|
||||
request_.setAttribute_(RequestDispatcher.FORWARD_REQUEST_URI, null);
|
||||
request_.setAttribute_(RequestDispatcher.FORWARD_CONTEXT_PATH, null);
|
||||
request_.setAttribute_(RequestDispatcher.FORWARD_QUERY_STRING, null);
|
||||
}
|
||||
}
|
||||
42
src/java/nginx/unit/HeaderNamesEnumeration.java
Normal file
42
src/java/nginx/unit/HeaderNamesEnumeration.java
Normal file
@@ -0,0 +1,42 @@
|
||||
package nginx.unit;
|
||||
|
||||
import java.lang.String;
|
||||
import java.util.Enumeration;
|
||||
import java.util.NoSuchElementException;
|
||||
|
||||
public class HeaderNamesEnumeration implements Enumeration<String> {
|
||||
|
||||
private long headers_ptr;
|
||||
private long size;
|
||||
private long pos = 0;
|
||||
|
||||
public HeaderNamesEnumeration(long _headers_ptr, long _size) {
|
||||
headers_ptr = _headers_ptr;
|
||||
size = _size;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean hasMoreElements()
|
||||
{
|
||||
if (pos >= size) {
|
||||
return false;
|
||||
}
|
||||
|
||||
pos = nextElementPos(headers_ptr, size, pos);
|
||||
return pos < size;
|
||||
}
|
||||
|
||||
static private native long nextElementPos(long headers_ptr, long size, long pos);
|
||||
|
||||
@Override
|
||||
public String nextElement()
|
||||
{
|
||||
if (pos >= size) {
|
||||
throw new NoSuchElementException();
|
||||
}
|
||||
|
||||
return nextElement(headers_ptr, size, pos++);
|
||||
}
|
||||
|
||||
static private native String nextElement(long headers_ptr, long size, long pos);
|
||||
}
|
||||
40
src/java/nginx/unit/HeadersEnumeration.java
Normal file
40
src/java/nginx/unit/HeadersEnumeration.java
Normal file
@@ -0,0 +1,40 @@
|
||||
package nginx.unit;
|
||||
|
||||
import java.lang.String;
|
||||
import java.util.Enumeration;
|
||||
|
||||
public class HeadersEnumeration implements Enumeration<String> {
|
||||
|
||||
private long headers_ptr;
|
||||
private long size;
|
||||
private long initial_pos;
|
||||
private long pos;
|
||||
|
||||
public HeadersEnumeration(long _headers_ptr, long _size, long _initial_pos) {
|
||||
headers_ptr = _headers_ptr;
|
||||
size = _size;
|
||||
initial_pos = _initial_pos;
|
||||
pos = _initial_pos;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean hasMoreElements()
|
||||
{
|
||||
if (pos >= size) {
|
||||
return false;
|
||||
}
|
||||
|
||||
pos = nextElementPos(headers_ptr, size, initial_pos, pos);
|
||||
return pos < size;
|
||||
}
|
||||
|
||||
static private native long nextElementPos(long headers_ptr, long size, long initial_pos, long pos);
|
||||
|
||||
@Override
|
||||
public String nextElement()
|
||||
{
|
||||
return nextElement(headers_ptr, size, initial_pos, pos++);
|
||||
}
|
||||
|
||||
static private native String nextElement(long headers_ptr, long size, long initial_pos, long pos);
|
||||
}
|
||||
88
src/java/nginx/unit/IncludeRequestWrapper.java
Normal file
88
src/java/nginx/unit/IncludeRequestWrapper.java
Normal file
@@ -0,0 +1,88 @@
|
||||
package nginx.unit;
|
||||
|
||||
import javax.servlet.DispatcherType;
|
||||
import javax.servlet.RequestDispatcher;
|
||||
import javax.servlet.ServletRequest;
|
||||
|
||||
public class IncludeRequestWrapper implements DynamicPathRequest
|
||||
{
|
||||
private final Request request_;
|
||||
|
||||
private final Object orig_servlet_path_attr;
|
||||
private final Object orig_path_info_attr;
|
||||
private final Object orig_uri_attr;
|
||||
private final Object orig_context_path_attr;
|
||||
private final Object orig_query_string_attr;
|
||||
|
||||
private final DispatcherType orig_dtype;
|
||||
|
||||
private String filter_path_;
|
||||
|
||||
public IncludeRequestWrapper(ServletRequest request)
|
||||
{
|
||||
if (request instanceof Request) {
|
||||
request_ = (Request) request;
|
||||
} else {
|
||||
request_ = (Request) request.getAttribute(Request.BARE);
|
||||
}
|
||||
|
||||
orig_servlet_path_attr = request_.getAttribute(RequestDispatcher.INCLUDE_SERVLET_PATH);
|
||||
orig_path_info_attr = request_.getAttribute(RequestDispatcher.INCLUDE_PATH_INFO);
|
||||
orig_uri_attr = request_.getAttribute(RequestDispatcher.INCLUDE_REQUEST_URI);
|
||||
orig_context_path_attr = request_.getAttribute(RequestDispatcher.INCLUDE_CONTEXT_PATH);
|
||||
orig_query_string_attr = request_.getAttribute(RequestDispatcher.INCLUDE_QUERY_STRING);
|
||||
|
||||
orig_dtype = request_.getDispatcherType();
|
||||
|
||||
request_.setAttribute_(RequestDispatcher.INCLUDE_CONTEXT_PATH, request_.getContextPath());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setDispatcherType(DispatcherType type)
|
||||
{
|
||||
request_.setDispatcherType(type);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setServletPath(String servlet_path, String path_info)
|
||||
{
|
||||
setServletPath(servlet_path, servlet_path, path_info);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setServletPath(String filter_path, String servlet_path, String path_info)
|
||||
{
|
||||
request_.setAttribute_(RequestDispatcher.INCLUDE_SERVLET_PATH, servlet_path);
|
||||
request_.setAttribute_(RequestDispatcher.INCLUDE_PATH_INFO, path_info);
|
||||
filter_path_ = filter_path;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setRequestURI(String uri)
|
||||
{
|
||||
request_.setAttribute_(RequestDispatcher.INCLUDE_REQUEST_URI, uri);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setQueryString(String query)
|
||||
{
|
||||
request_.setAttribute_(RequestDispatcher.INCLUDE_QUERY_STRING, query);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getFilterPath()
|
||||
{
|
||||
return filter_path_;
|
||||
}
|
||||
|
||||
public void close()
|
||||
{
|
||||
request_.setDispatcherType(orig_dtype);
|
||||
|
||||
request_.setAttribute_(RequestDispatcher.INCLUDE_SERVLET_PATH, orig_servlet_path_attr);
|
||||
request_.setAttribute_(RequestDispatcher.INCLUDE_PATH_INFO, orig_path_info_attr);
|
||||
request_.setAttribute_(RequestDispatcher.INCLUDE_REQUEST_URI, orig_uri_attr);
|
||||
request_.setAttribute_(RequestDispatcher.INCLUDE_CONTEXT_PATH, orig_context_path_attr);
|
||||
request_.setAttribute_(RequestDispatcher.INCLUDE_QUERY_STRING, orig_query_string_attr);
|
||||
}
|
||||
}
|
||||
117
src/java/nginx/unit/IncludeResponseWrapper.java
Normal file
117
src/java/nginx/unit/IncludeResponseWrapper.java
Normal file
@@ -0,0 +1,117 @@
|
||||
package nginx.unit;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
import java.nio.charset.Charset;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
|
||||
import javax.servlet.ServletResponse;
|
||||
import javax.servlet.http.Cookie;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
import javax.servlet.http.HttpServletResponseWrapper;
|
||||
|
||||
public class IncludeResponseWrapper extends HttpServletResponseWrapper {
|
||||
private static final Charset UTF_8 = StandardCharsets.UTF_8;
|
||||
|
||||
public IncludeResponseWrapper(ServletResponse response)
|
||||
{
|
||||
super((HttpServletResponse) response);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addCookie(Cookie cookie)
|
||||
{
|
||||
trace("addCookie: " + cookie.getName() + "=" + cookie.getValue());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addDateHeader(String name, long date)
|
||||
{
|
||||
trace("addDateHeader: " + name + ": " + date);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addHeader(String name, String value)
|
||||
{
|
||||
trace("addHeader: " + name + ": " + value);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addIntHeader(String name, int value)
|
||||
{
|
||||
trace("addIntHeader: " + name + ": " + value);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void sendRedirect(String location) throws IOException
|
||||
{
|
||||
trace("sendRedirect: " + location);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setDateHeader(String name, long date)
|
||||
{
|
||||
trace("setDateHeader: " + name + ": " + date);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setHeader(String name, String value)
|
||||
{
|
||||
trace("setHeader: " + name + ": " + value);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setIntHeader(String name, int value)
|
||||
{
|
||||
trace("setIntHeader: " + name + ": " + value);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setStatus(int sc)
|
||||
{
|
||||
trace("setStatus: " + sc);
|
||||
}
|
||||
|
||||
@Override
|
||||
@Deprecated
|
||||
public void setStatus(int sc, String sm)
|
||||
{
|
||||
trace("setStatus: " + sc + "; " + sm);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void reset()
|
||||
{
|
||||
trace("reset");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setCharacterEncoding(String charset)
|
||||
{
|
||||
trace("setCharacterEncoding " + charset);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setContentLength(int len)
|
||||
{
|
||||
trace("setContentLength: " + len);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setContentLengthLong(long len)
|
||||
{
|
||||
trace("setContentLengthLong: " + len);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setContentType(String type)
|
||||
{
|
||||
trace("setContentType: " + type);
|
||||
}
|
||||
|
||||
private void trace(String msg)
|
||||
{
|
||||
msg = "IncludeResponse." + msg;
|
||||
Response.trace(0, msg.getBytes(UTF_8));
|
||||
}
|
||||
}
|
||||
7
src/java/nginx/unit/InitParams.java
Normal file
7
src/java/nginx/unit/InitParams.java
Normal file
@@ -0,0 +1,7 @@
|
||||
package nginx.unit;
|
||||
|
||||
public interface InitParams {
|
||||
public boolean setInitParameter(String name, String value);
|
||||
|
||||
public String getInitParameter(String name);
|
||||
}
|
||||
90
src/java/nginx/unit/InputStream.java
Normal file
90
src/java/nginx/unit/InputStream.java
Normal file
@@ -0,0 +1,90 @@
|
||||
package nginx.unit;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
import javax.servlet.ReadListener;
|
||||
import javax.servlet.ServletInputStream;
|
||||
|
||||
public class InputStream extends ServletInputStream {
|
||||
|
||||
private long req_info_ptr;
|
||||
|
||||
public InputStream(long ptr)
|
||||
{
|
||||
req_info_ptr = ptr;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int readLine(byte[] b, int off, int len) throws IOException {
|
||||
|
||||
if (len <= 0) {
|
||||
return 0;
|
||||
}
|
||||
return readLine(req_info_ptr, b, off, len);
|
||||
}
|
||||
|
||||
private static native int readLine(long req_info_ptr, byte[] b, int off, int len);
|
||||
|
||||
|
||||
@Override
|
||||
public boolean isFinished()
|
||||
{
|
||||
return isFinished(req_info_ptr);
|
||||
}
|
||||
|
||||
private static native boolean isFinished(long req_info_ptr);
|
||||
|
||||
|
||||
@Override
|
||||
public boolean isReady()
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public void setReadListener(ReadListener listener)
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public int read() throws IOException
|
||||
{
|
||||
return read(req_info_ptr);
|
||||
}
|
||||
|
||||
private static native int read(long req_info_ptr);
|
||||
|
||||
|
||||
@Override
|
||||
public int read(byte b[], int off, int len) throws IOException {
|
||||
if (b == null) {
|
||||
throw new NullPointerException();
|
||||
} else if (off < 0 || len < 0 || len > b.length - off) {
|
||||
throw new IndexOutOfBoundsException();
|
||||
} else if (len == 0) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
return read(req_info_ptr, b, off, len);
|
||||
}
|
||||
|
||||
private static native int read(long req_info_ptr, byte b[], int off, int len);
|
||||
|
||||
|
||||
@Override
|
||||
public long skip(long n) throws IOException {
|
||||
return skip(req_info_ptr, n);
|
||||
}
|
||||
|
||||
private static native long skip(long req_info_ptr, long n);
|
||||
|
||||
|
||||
@Override
|
||||
public int available() throws IOException {
|
||||
return available(req_info_ptr);
|
||||
}
|
||||
|
||||
private static native int available(long req_info_ptr);
|
||||
}
|
||||
169
src/java/nginx/unit/JspPropertyGroup.java
Normal file
169
src/java/nginx/unit/JspPropertyGroup.java
Normal file
@@ -0,0 +1,169 @@
|
||||
package nginx.unit;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
|
||||
import javax.servlet.descriptor.JspPropertyGroupDescriptor;
|
||||
|
||||
import org.w3c.dom.Node;
|
||||
import org.w3c.dom.NodeList;
|
||||
|
||||
public class JspPropertyGroup implements JspPropertyGroupDescriptor
|
||||
{
|
||||
private final List<String> url_patterns_ = new ArrayList<>();
|
||||
private String el_ignored_ = null;
|
||||
private String page_encoding_ = null;
|
||||
private String scripting_invalid_ = null;
|
||||
private String is_xml_ = null;
|
||||
private final List<String> include_preludes_ = new ArrayList<>();
|
||||
private final List<String> include_codas_ = new ArrayList<>();
|
||||
|
||||
private String deffered_syntax_allowed_as_literal_ = null;
|
||||
private String trim_directive_whitespaces_ = null;
|
||||
private String default_content_type_ = null;
|
||||
private String buffer_ = null;
|
||||
private String error_on_undeclared_namespace_ = null;
|
||||
|
||||
public JspPropertyGroup(NodeList nodes)
|
||||
{
|
||||
for (int i = 0; i < nodes.getLength(); i++) {
|
||||
Node node = nodes.item(i);
|
||||
String tag_name = node.getNodeName();
|
||||
|
||||
if (tag_name.equals("url-pattern")) {
|
||||
url_patterns_.add(node.getTextContent().trim());
|
||||
continue;
|
||||
}
|
||||
|
||||
if (tag_name.equals("el-ignored")) {
|
||||
el_ignored_ = node.getTextContent().trim();
|
||||
continue;
|
||||
}
|
||||
|
||||
if (tag_name.equals("page-encoding")) {
|
||||
page_encoding_ = node.getTextContent().trim();
|
||||
continue;
|
||||
}
|
||||
|
||||
if (tag_name.equals("scripting-invalid")) {
|
||||
scripting_invalid_ = node.getTextContent().trim();
|
||||
continue;
|
||||
}
|
||||
|
||||
if (tag_name.equals("is-xml")) {
|
||||
is_xml_ = node.getTextContent().trim();
|
||||
continue;
|
||||
}
|
||||
|
||||
if (tag_name.equals("include-prelude")) {
|
||||
include_preludes_.add(node.getTextContent().trim());
|
||||
continue;
|
||||
}
|
||||
|
||||
if (tag_name.equals("include-coda")) {
|
||||
include_codas_.add(node.getTextContent().trim());
|
||||
continue;
|
||||
}
|
||||
|
||||
if (tag_name.equals("deferred-syntax-allowed-as-literal")) {
|
||||
deffered_syntax_allowed_as_literal_ = node.getTextContent().trim();
|
||||
continue;
|
||||
}
|
||||
|
||||
if (tag_name.equals("trim-directive-whitespaces")) {
|
||||
trim_directive_whitespaces_ = node.getTextContent().trim();
|
||||
continue;
|
||||
}
|
||||
|
||||
if (tag_name.equals("default-content-type")) {
|
||||
default_content_type_ = node.getTextContent().trim();
|
||||
continue;
|
||||
}
|
||||
|
||||
if (tag_name.equals("buffer")) {
|
||||
buffer_ = node.getTextContent().trim();
|
||||
continue;
|
||||
}
|
||||
|
||||
if (tag_name.equals("error-on-undeclared-namespace")) {
|
||||
error_on_undeclared_namespace_ = node.getTextContent().trim();
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public Collection<String> getUrlPatterns()
|
||||
{
|
||||
return new ArrayList<>(url_patterns_);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getElIgnored()
|
||||
{
|
||||
return el_ignored_;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getPageEncoding()
|
||||
{
|
||||
return page_encoding_;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getScriptingInvalid()
|
||||
{
|
||||
return scripting_invalid_;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getIsXml()
|
||||
{
|
||||
return is_xml_;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Collection<String> getIncludePreludes()
|
||||
{
|
||||
return new ArrayList<>(include_preludes_);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Collection<String> getIncludeCodas()
|
||||
{
|
||||
return new ArrayList<>(include_codas_);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getDeferredSyntaxAllowedAsLiteral()
|
||||
{
|
||||
return deffered_syntax_allowed_as_literal_;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getTrimDirectiveWhitespaces()
|
||||
{
|
||||
return trim_directive_whitespaces_;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getDefaultContentType()
|
||||
{
|
||||
return default_content_type_;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getBuffer()
|
||||
{
|
||||
return buffer_;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getErrorOnUndeclaredNamespace()
|
||||
{
|
||||
return error_on_undeclared_namespace_;
|
||||
}
|
||||
}
|
||||
|
||||
68
src/java/nginx/unit/OutputStream.java
Normal file
68
src/java/nginx/unit/OutputStream.java
Normal file
@@ -0,0 +1,68 @@
|
||||
package nginx.unit;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
import javax.servlet.ServletOutputStream;
|
||||
import javax.servlet.WriteListener;
|
||||
|
||||
public class OutputStream extends ServletOutputStream {
|
||||
|
||||
private long req_info_ptr;
|
||||
|
||||
public OutputStream(long ptr) {
|
||||
req_info_ptr = ptr;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void write(int b) throws IOException
|
||||
{
|
||||
write(req_info_ptr, b);
|
||||
}
|
||||
|
||||
private static native void write(long req_info_ptr, int b);
|
||||
|
||||
|
||||
@Override
|
||||
public void write(byte b[], int off, int len) throws IOException
|
||||
{
|
||||
if (b == null) {
|
||||
throw new NullPointerException();
|
||||
} else if ((off < 0) || (off > b.length) || (len < 0) ||
|
||||
((off + len) > b.length) || ((off + len) < 0)) {
|
||||
throw new IndexOutOfBoundsException();
|
||||
} else if (len == 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
write(req_info_ptr, b, off, len);
|
||||
}
|
||||
|
||||
private static native void write(long req_info_ptr, byte b[], int off, int len);
|
||||
|
||||
@Override
|
||||
public void flush()
|
||||
{
|
||||
flush(req_info_ptr);
|
||||
}
|
||||
|
||||
private static native void flush(long req_info_ptr);
|
||||
|
||||
@Override
|
||||
public void close()
|
||||
{
|
||||
close(req_info_ptr);
|
||||
}
|
||||
|
||||
private static native void close(long req_info_ptr);
|
||||
|
||||
@Override
|
||||
public boolean isReady()
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setWriteListener(WriteListener listener)
|
||||
{
|
||||
}
|
||||
}
|
||||
1123
src/java/nginx/unit/Request.java
Normal file
1123
src/java/nginx/unit/Request.java
Normal file
File diff suppressed because it is too large
Load Diff
40
src/java/nginx/unit/RequestAttrProxy.java
Normal file
40
src/java/nginx/unit/RequestAttrProxy.java
Normal file
@@ -0,0 +1,40 @@
|
||||
package nginx.unit;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import javax.servlet.ServletRequestAttributeEvent;
|
||||
import javax.servlet.ServletRequestAttributeListener;
|
||||
|
||||
public class RequestAttrProxy implements ServletRequestAttributeListener
|
||||
{
|
||||
private final List<ServletRequestAttributeListener> listeners_;
|
||||
|
||||
public RequestAttrProxy(List<ServletRequestAttributeListener> listeners)
|
||||
{
|
||||
listeners_ = listeners;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void attributeAdded(ServletRequestAttributeEvent srae)
|
||||
{
|
||||
for (ServletRequestAttributeListener l : listeners_) {
|
||||
l.attributeAdded(srae);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void attributeReplaced(ServletRequestAttributeEvent srae)
|
||||
{
|
||||
for (ServletRequestAttributeListener l : listeners_) {
|
||||
l.attributeReplaced(srae);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void attributeRemoved(ServletRequestAttributeEvent srae)
|
||||
{
|
||||
for (ServletRequestAttributeListener l : listeners_) {
|
||||
l.attributeRemoved(srae);
|
||||
}
|
||||
}
|
||||
}
|
||||
817
src/java/nginx/unit/Response.java
Normal file
817
src/java/nginx/unit/Response.java
Normal file
@@ -0,0 +1,817 @@
|
||||
package nginx.unit;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.OutputStreamWriter;
|
||||
import java.io.PrintWriter;
|
||||
|
||||
import java.lang.IllegalArgumentException;
|
||||
import java.lang.String;
|
||||
|
||||
import java.net.URI;
|
||||
import java.net.URISyntaxException;
|
||||
|
||||
import java.nio.charset.Charset;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
|
||||
import java.text.SimpleDateFormat;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.Date;
|
||||
import java.util.Enumeration;
|
||||
import java.util.Locale;
|
||||
import java.util.TimeZone;
|
||||
import java.util.Vector;
|
||||
|
||||
import javax.servlet.DispatcherType;
|
||||
import javax.servlet.RequestDispatcher;
|
||||
import javax.servlet.ServletOutputStream;
|
||||
import javax.servlet.http.Cookie;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
|
||||
import org.eclipse.jetty.http.MimeTypes;
|
||||
import org.eclipse.jetty.util.StringUtil;
|
||||
|
||||
public class Response implements HttpServletResponse {
|
||||
|
||||
private long req_info_ptr;
|
||||
|
||||
private static final String defaultCharacterEncoding = "iso-8859-1";
|
||||
private String characterEncoding = defaultCharacterEncoding;
|
||||
private String contentType = null;
|
||||
private String contentTypeHeader = null;
|
||||
|
||||
private static final Charset ISO_8859_1 = StandardCharsets.ISO_8859_1;
|
||||
private static final Charset UTF_8 = StandardCharsets.UTF_8;
|
||||
|
||||
private static final String CONTENT_TYPE = "Content-Type";
|
||||
private static final byte[] SET_COOKIE_BYTES = "Set-Cookie".getBytes(ISO_8859_1);
|
||||
private static final byte[] EXPIRES_BYTES = "Expires".getBytes(ISO_8859_1);
|
||||
|
||||
/**
|
||||
* The only date format permitted when generating HTTP headers.
|
||||
*/
|
||||
public static final String RFC1123_DATE =
|
||||
"EEE, dd MMM yyyy HH:mm:ss zzz";
|
||||
|
||||
private static final SimpleDateFormat format =
|
||||
new SimpleDateFormat(RFC1123_DATE, Locale.US);
|
||||
|
||||
private static final String ZERO_DATE_STRING = dateToString(0);
|
||||
private static final byte[] ZERO_DATE_BYTES = ZERO_DATE_STRING.getBytes(ISO_8859_1);
|
||||
|
||||
/**
|
||||
* If this string is found within the comment of a cookie added with {@link #addCookie(Cookie)}, then the cookie
|
||||
* will be set as HTTP ONLY.
|
||||
*/
|
||||
public final static String HTTP_ONLY_COMMENT = "__HTTP_ONLY__";
|
||||
|
||||
private OutputStream outputStream = null;
|
||||
|
||||
private PrintWriter writer = null;
|
||||
|
||||
|
||||
public Response(long ptr) {
|
||||
req_info_ptr = ptr;
|
||||
}
|
||||
|
||||
/**
|
||||
* Format a set cookie value by RFC6265
|
||||
*
|
||||
* @param name the name
|
||||
* @param value the value
|
||||
* @param domain the domain
|
||||
* @param path the path
|
||||
* @param maxAge the maximum age
|
||||
* @param isSecure true if secure cookie
|
||||
* @param isHttpOnly true if for http only
|
||||
*/
|
||||
public void addSetRFC6265Cookie(
|
||||
final String name,
|
||||
final String value,
|
||||
final String domain,
|
||||
final String path,
|
||||
final long maxAge,
|
||||
final boolean isSecure,
|
||||
final boolean isHttpOnly)
|
||||
{
|
||||
// Check arguments
|
||||
if (name == null || name.length() == 0) {
|
||||
throw new IllegalArgumentException("Bad cookie name");
|
||||
}
|
||||
|
||||
// Name is checked for legality by servlet spec, but can also be passed directly so check again for quoting
|
||||
// Per RFC6265, Cookie.name follows RFC2616 Section 2.2 token rules
|
||||
//Syntax.requireValidRFC2616Token(name, "RFC6265 Cookie name");
|
||||
// Ensure that Per RFC6265, Cookie.value follows syntax rules
|
||||
//Syntax.requireValidRFC6265CookieValue(value);
|
||||
|
||||
// Format value and params
|
||||
StringBuilder buf = new StringBuilder();
|
||||
buf.append(name).append('=').append(value == null ? "" : value);
|
||||
|
||||
// Append path
|
||||
if (path != null && path.length() > 0) {
|
||||
buf.append(";Path=").append(path);
|
||||
}
|
||||
|
||||
// Append domain
|
||||
if (domain != null && domain.length() > 0) {
|
||||
buf.append(";Domain=").append(domain);
|
||||
}
|
||||
|
||||
// Handle max-age and/or expires
|
||||
if (maxAge >= 0) {
|
||||
// Always use expires
|
||||
// This is required as some browser (M$ this means you!) don't handle max-age even with v1 cookies
|
||||
buf.append(";Expires=");
|
||||
if (maxAge == 0)
|
||||
buf.append(ZERO_DATE_STRING);
|
||||
else
|
||||
buf.append(dateToString(System.currentTimeMillis() + 1000L * maxAge));
|
||||
|
||||
buf.append(";Max-Age=");
|
||||
buf.append(maxAge);
|
||||
}
|
||||
|
||||
// add the other fields
|
||||
if (isSecure)
|
||||
buf.append(";Secure");
|
||||
if (isHttpOnly)
|
||||
buf.append(";HttpOnly");
|
||||
|
||||
// add the set cookie
|
||||
addHeader(req_info_ptr, SET_COOKIE_BYTES,
|
||||
buf.toString().getBytes(ISO_8859_1));
|
||||
|
||||
// Expire responses with set-cookie headers so they do not get cached.
|
||||
setHeader(req_info_ptr, EXPIRES_BYTES, ZERO_DATE_BYTES);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addCookie(Cookie cookie)
|
||||
{
|
||||
trace("addCookie: " + cookie.getName() + "=" + cookie.getValue());
|
||||
|
||||
if (StringUtil.isBlank(cookie.getName())) {
|
||||
throw new IllegalArgumentException("Cookie.name cannot be blank/null");
|
||||
}
|
||||
|
||||
if (isCommitted()) {
|
||||
return;
|
||||
}
|
||||
|
||||
addCookie_(cookie);
|
||||
}
|
||||
|
||||
private void addCookie_(Cookie cookie)
|
||||
{
|
||||
String comment = cookie.getComment();
|
||||
boolean httpOnly = false;
|
||||
|
||||
if (comment != null && comment.contains(HTTP_ONLY_COMMENT)) {
|
||||
httpOnly = true;
|
||||
}
|
||||
|
||||
addSetRFC6265Cookie(cookie.getName(),
|
||||
cookie.getValue(),
|
||||
cookie.getDomain(),
|
||||
cookie.getPath(),
|
||||
cookie.getMaxAge(),
|
||||
cookie.getSecure(),
|
||||
httpOnly || cookie.isHttpOnly());
|
||||
}
|
||||
|
||||
public void addSessionIdCookie(Cookie cookie)
|
||||
{
|
||||
trace("addSessionIdCookie: " + cookie.getName() + "=" + cookie.getValue());
|
||||
|
||||
if (isCommitted()) {
|
||||
/*
|
||||
9.3 The Include Method
|
||||
|
||||
... any call to HttpServletRequest.getSession() or
|
||||
HttpServletRequest.getSession(boolean) that would require
|
||||
adding a Cookie response header must throw an
|
||||
IllegalStateException if the response has been committed.
|
||||
*/
|
||||
throw new IllegalStateException("Response already sent");
|
||||
}
|
||||
|
||||
addCookie_(cookie);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addDateHeader(String name, long date)
|
||||
{
|
||||
trace("addDateHeader: " + name + ": " + date);
|
||||
|
||||
if (isCommitted()) {
|
||||
return;
|
||||
}
|
||||
|
||||
String value = dateToString(date);
|
||||
|
||||
addHeader(req_info_ptr, name.getBytes(ISO_8859_1),
|
||||
value.getBytes(ISO_8859_1));
|
||||
}
|
||||
|
||||
private static String dateToString(long date)
|
||||
{
|
||||
Date dateValue = new Date(date);
|
||||
format.setTimeZone(TimeZone.getTimeZone("GMT"));
|
||||
return format.format(dateValue);
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public void addHeader(String name, String value)
|
||||
{
|
||||
trace("addHeader: " + name + ": " + value);
|
||||
|
||||
if (value == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (isCommitted()) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (CONTENT_TYPE.equalsIgnoreCase(name)) {
|
||||
setContentType(value);
|
||||
return;
|
||||
}
|
||||
|
||||
addHeader(req_info_ptr, name.getBytes(ISO_8859_1),
|
||||
value.getBytes(ISO_8859_1));
|
||||
}
|
||||
|
||||
private static native void addHeader(long req_info_ptr, byte[] name, byte[] value);
|
||||
|
||||
|
||||
@Override
|
||||
public void addIntHeader(String name, int value)
|
||||
{
|
||||
trace("addIntHeader: " + name + ": " + value);
|
||||
|
||||
if (isCommitted()) {
|
||||
return;
|
||||
}
|
||||
|
||||
addIntHeader(req_info_ptr, name.getBytes(ISO_8859_1), value);
|
||||
}
|
||||
|
||||
private static native void addIntHeader(long req_info_ptr, byte[] name, int value);
|
||||
|
||||
|
||||
@Override
|
||||
public boolean containsHeader(String name)
|
||||
{
|
||||
trace("containsHeader: " + name);
|
||||
|
||||
return containsHeader(req_info_ptr, name.getBytes(ISO_8859_1));
|
||||
}
|
||||
|
||||
private static native boolean containsHeader(long req_info_ptr, byte[] name);
|
||||
|
||||
|
||||
@Override
|
||||
@Deprecated
|
||||
public String encodeRedirectUrl(String url)
|
||||
{
|
||||
return encodeRedirectURL(url);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String encodeRedirectURL(String url)
|
||||
{
|
||||
log("encodeRedirectURL: " + url);
|
||||
|
||||
return url;
|
||||
}
|
||||
|
||||
@Override
|
||||
@Deprecated
|
||||
public String encodeUrl(String url)
|
||||
{
|
||||
return encodeURL(url);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String encodeURL(String url)
|
||||
{
|
||||
log("encodeURL: " + url);
|
||||
|
||||
return url;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getHeader(String name)
|
||||
{
|
||||
trace("getHeader: " + name);
|
||||
|
||||
return getHeader(req_info_ptr, name.getBytes(ISO_8859_1));
|
||||
}
|
||||
|
||||
private static native String getHeader(long req_info_ptr, byte[] name);
|
||||
|
||||
|
||||
@Override
|
||||
public Collection<String> getHeaderNames()
|
||||
{
|
||||
trace("getHeaderNames");
|
||||
|
||||
Enumeration<String> e = getHeaderNames(req_info_ptr);
|
||||
if (e == null) {
|
||||
return Collections.emptyList();
|
||||
}
|
||||
|
||||
return Collections.list(e);
|
||||
}
|
||||
|
||||
private static native Enumeration<String> getHeaderNames(long req_info_ptr);
|
||||
|
||||
|
||||
@Override
|
||||
public Collection<String> getHeaders(String name)
|
||||
{
|
||||
trace("getHeaders: " + name);
|
||||
|
||||
Enumeration<String> e = getHeaders(req_info_ptr, name.getBytes(ISO_8859_1));
|
||||
if (e == null) {
|
||||
return Collections.emptyList();
|
||||
}
|
||||
|
||||
return Collections.list(e);
|
||||
}
|
||||
|
||||
private static native Enumeration<String> getHeaders(long req_info_ptr, byte[] name);
|
||||
|
||||
|
||||
@Override
|
||||
public int getStatus()
|
||||
{
|
||||
trace("getStatus");
|
||||
|
||||
return getStatus(req_info_ptr);
|
||||
}
|
||||
|
||||
private static native int getStatus(long req_info_ptr);
|
||||
|
||||
|
||||
@Override
|
||||
public void sendError(int sc) throws IOException
|
||||
{
|
||||
sendError(sc, null);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void sendError(int sc, String msg) throws IOException
|
||||
{
|
||||
trace("sendError: " + sc + ", " + msg);
|
||||
|
||||
if (isCommitted()) {
|
||||
throw new IllegalStateException("Response already sent");
|
||||
}
|
||||
|
||||
setStatus(sc);
|
||||
|
||||
Request request = getRequest(req_info_ptr);
|
||||
|
||||
// If we are allowed to have a body, then produce the error page.
|
||||
if (sc != SC_NO_CONTENT && sc != SC_NOT_MODIFIED &&
|
||||
sc != SC_PARTIAL_CONTENT && sc >= SC_OK)
|
||||
{
|
||||
request.setAttribute_(RequestDispatcher.ERROR_STATUS_CODE, sc);
|
||||
request.setAttribute_(RequestDispatcher.ERROR_MESSAGE, msg);
|
||||
request.setAttribute_(RequestDispatcher.ERROR_REQUEST_URI,
|
||||
request.getRequestURI());
|
||||
/*
|
||||
request.setAttribute_(RequestDispatcher.ERROR_SERVLET_NAME,
|
||||
request.getServletName());
|
||||
*/
|
||||
}
|
||||
|
||||
/*
|
||||
Avoid commit and give chance for error handlers.
|
||||
|
||||
if (!request.isAsyncStarted()) {
|
||||
commit();
|
||||
}
|
||||
*/
|
||||
}
|
||||
|
||||
private static native Request getRequest(long req_info_ptr);
|
||||
|
||||
private void commit()
|
||||
{
|
||||
if (writer != null) {
|
||||
writer.close();
|
||||
|
||||
} else if (outputStream != null) {
|
||||
outputStream.close();
|
||||
|
||||
} else {
|
||||
commit(req_info_ptr);
|
||||
}
|
||||
}
|
||||
|
||||
private static native void commit(long req_info_ptr);
|
||||
|
||||
|
||||
@Override
|
||||
public void sendRedirect(String location) throws IOException
|
||||
{
|
||||
trace("sendRedirect: " + location);
|
||||
|
||||
if (isCommitted()) {
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
URI uri = new URI(location);
|
||||
|
||||
if (!uri.isAbsolute()) {
|
||||
URI req_uri = new URI(getRequest(req_info_ptr).getRequestURL().toString());
|
||||
uri = req_uri.resolve(uri);
|
||||
|
||||
location = uri.toString();
|
||||
}
|
||||
} catch (URISyntaxException e) {
|
||||
log("sendRedirect: failed to send redirect: " + e);
|
||||
return;
|
||||
}
|
||||
|
||||
sendRedirect(req_info_ptr, location.getBytes(ISO_8859_1));
|
||||
}
|
||||
|
||||
private static native void sendRedirect(long req_info_ptr, byte[] location);
|
||||
|
||||
|
||||
@Override
|
||||
public void setDateHeader(String name, long date)
|
||||
{
|
||||
trace("setDateHeader: " + name + ": " + date);
|
||||
|
||||
if (isCommitted()) {
|
||||
return;
|
||||
}
|
||||
|
||||
String value = dateToString(date);
|
||||
|
||||
setHeader(req_info_ptr, name.getBytes(ISO_8859_1),
|
||||
value.getBytes(ISO_8859_1));
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public void setHeader(String name, String value)
|
||||
{
|
||||
trace("setHeader: " + name + ": " + value);
|
||||
|
||||
if (isCommitted()) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (CONTENT_TYPE.equalsIgnoreCase(name)) {
|
||||
setContentType(value);
|
||||
return;
|
||||
}
|
||||
|
||||
/*
|
||||
* When value is null container behaviour is undefined.
|
||||
* - Tomcat ignores setHeader call;
|
||||
* - Jetty & Resin acts as removeHeader;
|
||||
*/
|
||||
if (value == null) {
|
||||
removeHeader(req_info_ptr, name.getBytes(ISO_8859_1));
|
||||
return;
|
||||
}
|
||||
|
||||
setHeader(req_info_ptr, name.getBytes(ISO_8859_1),
|
||||
value.getBytes(ISO_8859_1));
|
||||
}
|
||||
|
||||
private static native void setHeader(long req_info_ptr, byte[] name, byte[] value);
|
||||
|
||||
private static native void removeHeader(long req_info_ptr, byte[] name);
|
||||
|
||||
@Override
|
||||
public void setIntHeader(String name, int value)
|
||||
{
|
||||
trace("setIntHeader: " + name + ": " + value);
|
||||
|
||||
if (isCommitted()) {
|
||||
return;
|
||||
}
|
||||
|
||||
setIntHeader(req_info_ptr, name.getBytes(ISO_8859_1), value);
|
||||
}
|
||||
|
||||
private static native void setIntHeader(long req_info_ptr, byte[] name, int value);
|
||||
|
||||
|
||||
@Override
|
||||
public void setStatus(int sc)
|
||||
{
|
||||
trace("setStatus: " + sc);
|
||||
|
||||
if (isCommitted()) {
|
||||
return;
|
||||
}
|
||||
|
||||
setStatus(req_info_ptr, sc);
|
||||
}
|
||||
|
||||
private static native void setStatus(long req_info_ptr, int sc);
|
||||
|
||||
|
||||
@Override
|
||||
@Deprecated
|
||||
public void setStatus(int sc, String sm)
|
||||
{
|
||||
trace("setStatus: " + sc + "; " + sm);
|
||||
|
||||
if (isCommitted()) {
|
||||
return;
|
||||
}
|
||||
|
||||
setStatus(req_info_ptr, sc);
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public void flushBuffer() throws IOException
|
||||
{
|
||||
trace("flushBuffer");
|
||||
|
||||
if (writer != null) {
|
||||
writer.flush();
|
||||
}
|
||||
|
||||
if (outputStream != null) {
|
||||
outputStream.flush();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getBufferSize()
|
||||
{
|
||||
trace("getBufferSize");
|
||||
|
||||
return getBufferSize(req_info_ptr);
|
||||
}
|
||||
|
||||
public static native int getBufferSize(long req_info_ptr);
|
||||
|
||||
|
||||
@Override
|
||||
public String getCharacterEncoding()
|
||||
{
|
||||
trace("getCharacterEncoding");
|
||||
|
||||
return characterEncoding;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getContentType()
|
||||
{
|
||||
/* In JIRA decorator get content type called after commit. */
|
||||
|
||||
String res = contentTypeHeader;
|
||||
|
||||
trace("getContentType: " + res);
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
private static native String getContentType(long req_info_ptr);
|
||||
|
||||
@Override
|
||||
public Locale getLocale()
|
||||
{
|
||||
log("getLocale");
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ServletOutputStream getOutputStream() throws IOException
|
||||
{
|
||||
trace("getOutputStream");
|
||||
|
||||
if (writer != null) {
|
||||
throw new IllegalStateException("Writer already created");
|
||||
}
|
||||
|
||||
if (outputStream == null) {
|
||||
outputStream = new OutputStream(req_info_ptr);
|
||||
}
|
||||
|
||||
return outputStream;
|
||||
}
|
||||
|
||||
@Override
|
||||
public PrintWriter getWriter() throws IOException
|
||||
{
|
||||
trace("getWriter ( characterEncoding = '" + characterEncoding + "' )");
|
||||
|
||||
if (outputStream != null) {
|
||||
throw new IllegalStateException("OutputStream already created");
|
||||
}
|
||||
|
||||
if (writer == null) {
|
||||
ServletOutputStream stream = new OutputStream(req_info_ptr);
|
||||
|
||||
writer = new PrintWriter(
|
||||
new OutputStreamWriter(stream, Charset.forName(characterEncoding)),
|
||||
false);
|
||||
}
|
||||
|
||||
return writer;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isCommitted()
|
||||
{
|
||||
trace("isCommitted");
|
||||
|
||||
return isCommitted(req_info_ptr);
|
||||
}
|
||||
|
||||
public static native boolean isCommitted(long req_info_ptr);
|
||||
|
||||
@Override
|
||||
public void reset()
|
||||
{
|
||||
trace("reset");
|
||||
|
||||
if (isCommitted()) {
|
||||
return;
|
||||
}
|
||||
|
||||
reset(req_info_ptr);
|
||||
|
||||
writer = null;
|
||||
outputStream = null;
|
||||
}
|
||||
|
||||
public static native void reset(long req_info_ptr);
|
||||
|
||||
@Override
|
||||
public void resetBuffer()
|
||||
{
|
||||
trace("resetBuffer");
|
||||
|
||||
resetBuffer(req_info_ptr);
|
||||
|
||||
writer = null;
|
||||
outputStream = null;
|
||||
}
|
||||
|
||||
public static native void resetBuffer(long req_info_ptr);
|
||||
|
||||
@Override
|
||||
public void setBufferSize(int size)
|
||||
{
|
||||
trace("setBufferSize: " + size);
|
||||
|
||||
setBufferSize(req_info_ptr, size);
|
||||
}
|
||||
|
||||
public static native void setBufferSize(long req_info_ptr, int size);
|
||||
|
||||
@Override
|
||||
public void setCharacterEncoding(String charset)
|
||||
{
|
||||
trace("setCharacterEncoding " + charset);
|
||||
|
||||
if (isCommitted()) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (charset == null) {
|
||||
if (writer != null
|
||||
&& !characterEncoding.equalsIgnoreCase(defaultCharacterEncoding))
|
||||
{
|
||||
/* TODO throw */
|
||||
return;
|
||||
}
|
||||
|
||||
characterEncoding = defaultCharacterEncoding;
|
||||
} else {
|
||||
if (writer != null
|
||||
&& !characterEncoding.equalsIgnoreCase(charset))
|
||||
{
|
||||
/* TODO throw */
|
||||
return;
|
||||
}
|
||||
|
||||
characterEncoding = charset;
|
||||
}
|
||||
|
||||
if (contentType != null) {
|
||||
String type = contentType + ";charset=" + characterEncoding;
|
||||
|
||||
contentTypeHeader = type;
|
||||
|
||||
setContentType(req_info_ptr, type.getBytes(ISO_8859_1));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public void setContentLength(int len)
|
||||
{
|
||||
trace("setContentLength: " + len);
|
||||
|
||||
if (isCommitted()) {
|
||||
return;
|
||||
}
|
||||
|
||||
setContentLength(req_info_ptr, len);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setContentLengthLong(long len)
|
||||
{
|
||||
trace("setContentLengthLong: " + len);
|
||||
|
||||
if (isCommitted()) {
|
||||
return;
|
||||
}
|
||||
|
||||
setContentLength(req_info_ptr, len);
|
||||
}
|
||||
|
||||
private static native void setContentLength(long req_info_ptr, long len);
|
||||
|
||||
|
||||
@Override
|
||||
public void setContentType(String type)
|
||||
{
|
||||
trace("setContentType: " + type);
|
||||
|
||||
if (isCommitted()) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (type == null) {
|
||||
removeContentType(req_info_ptr);
|
||||
contentType = null;
|
||||
contentTypeHeader = null;
|
||||
return;
|
||||
}
|
||||
|
||||
String charset = MimeTypes.getCharsetFromContentType(type);
|
||||
String ctype = MimeTypes.getContentTypeWithoutCharset(type);
|
||||
|
||||
if (writer != null
|
||||
&& charset != null
|
||||
&& !characterEncoding.equalsIgnoreCase(charset))
|
||||
{
|
||||
/* To late to change character encoding */
|
||||
charset = characterEncoding;
|
||||
type = ctype + ";charset=" + characterEncoding;
|
||||
}
|
||||
|
||||
if (charset == null) {
|
||||
type = type + ";charset=" + characterEncoding;
|
||||
} else {
|
||||
characterEncoding = charset;
|
||||
}
|
||||
|
||||
contentType = ctype;
|
||||
contentTypeHeader = type;
|
||||
|
||||
setContentType(req_info_ptr, type.getBytes(ISO_8859_1));
|
||||
}
|
||||
|
||||
private static native void setContentType(long req_info_ptr, byte[] type);
|
||||
|
||||
private static native void removeContentType(long req_info_ptr);
|
||||
|
||||
|
||||
@Override
|
||||
public void setLocale(Locale loc)
|
||||
{
|
||||
log("setLocale: " + loc);
|
||||
}
|
||||
|
||||
private void log(String msg)
|
||||
{
|
||||
msg = "Response." + msg;
|
||||
log(req_info_ptr, msg.getBytes(UTF_8));
|
||||
}
|
||||
|
||||
public static native void log(long req_info_ptr, byte[] msg);
|
||||
|
||||
|
||||
private void trace(String msg)
|
||||
{
|
||||
msg = "Response." + msg;
|
||||
trace(req_info_ptr, msg.getBytes(UTF_8));
|
||||
}
|
||||
|
||||
public static native void trace(long req_info_ptr, byte[] msg);
|
||||
}
|
||||
251
src/java/nginx/unit/Session.java
Normal file
251
src/java/nginx/unit/Session.java
Normal file
@@ -0,0 +1,251 @@
|
||||
package nginx.unit;
|
||||
|
||||
import java.io.Serializable;
|
||||
|
||||
import javax.servlet.ServletContext;
|
||||
import javax.servlet.http.HttpSession;
|
||||
import javax.servlet.http.HttpSessionAttributeListener;
|
||||
import javax.servlet.http.HttpSessionBindingEvent;
|
||||
import javax.servlet.http.HttpSessionBindingListener;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.Date;
|
||||
import java.util.Enumeration;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* @author Andrey Kazankov
|
||||
*/
|
||||
public class Session implements HttpSession, Serializable
|
||||
{
|
||||
private final Map<String, Object> attributes = new HashMap<>();
|
||||
private final long creation_time = new Date().getTime();
|
||||
private long last_access_time = creation_time;
|
||||
private long access_time = creation_time;
|
||||
private int max_inactive_interval;
|
||||
private String id;
|
||||
private final Context context;
|
||||
private boolean is_new = true;
|
||||
private final HttpSessionAttributeListener attr_listener;
|
||||
|
||||
public Session(Context context, String id,
|
||||
HttpSessionAttributeListener al, int max_inactive_interval)
|
||||
{
|
||||
this.id = id;
|
||||
this.context = context;
|
||||
attr_listener = al;
|
||||
this.max_inactive_interval = max_inactive_interval;
|
||||
}
|
||||
|
||||
public void setId(String id)
|
||||
{
|
||||
this.id = id;
|
||||
}
|
||||
|
||||
@Override
|
||||
public long getCreationTime()
|
||||
{
|
||||
return creation_time;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getId()
|
||||
{
|
||||
return id;
|
||||
}
|
||||
|
||||
@Override
|
||||
public long getLastAccessedTime()
|
||||
{
|
||||
return last_access_time;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ServletContext getServletContext()
|
||||
{
|
||||
return context;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setMaxInactiveInterval(int i)
|
||||
{
|
||||
max_inactive_interval = i;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getMaxInactiveInterval()
|
||||
{
|
||||
return max_inactive_interval;
|
||||
}
|
||||
|
||||
@Deprecated
|
||||
@Override
|
||||
public javax.servlet.http.HttpSessionContext getSessionContext()
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object getAttribute(String s)
|
||||
{
|
||||
synchronized (attributes) {
|
||||
return attributes.get(s);
|
||||
}
|
||||
}
|
||||
|
||||
@Deprecated
|
||||
@Override
|
||||
public Object getValue(String s)
|
||||
{
|
||||
return getAttribute(s);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Enumeration<String> getAttributeNames()
|
||||
{
|
||||
synchronized (attributes) {
|
||||
return Collections.enumeration(attributes.keySet());
|
||||
}
|
||||
}
|
||||
|
||||
@Deprecated
|
||||
@Override
|
||||
public String[] getValueNames()
|
||||
{
|
||||
synchronized (attributes) {
|
||||
return attributes.keySet().toArray(new String[attributes.keySet().size()]);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setAttribute(String s, Object o)
|
||||
{
|
||||
Object old;
|
||||
|
||||
if (o != null && o instanceof HttpSessionBindingListener) {
|
||||
HttpSessionBindingListener l = (HttpSessionBindingListener) o;
|
||||
HttpSessionBindingEvent e = new HttpSessionBindingEvent(this, s);
|
||||
|
||||
l.valueBound(e);
|
||||
}
|
||||
|
||||
synchronized (attributes) {
|
||||
if (o != null) {
|
||||
old = attributes.put(s, o);
|
||||
} else {
|
||||
old = attributes.remove(s);
|
||||
}
|
||||
}
|
||||
|
||||
if (old != null && old instanceof HttpSessionBindingListener) {
|
||||
HttpSessionBindingListener l = (HttpSessionBindingListener) old;
|
||||
HttpSessionBindingEvent e = new HttpSessionBindingEvent(this, s);
|
||||
|
||||
l.valueUnbound(e);
|
||||
}
|
||||
|
||||
if (attr_listener == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (o == null) {
|
||||
if (old != null) {
|
||||
HttpSessionBindingEvent e = new HttpSessionBindingEvent(this, s, old);
|
||||
attr_listener.attributeRemoved(e);
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
if (old != null) {
|
||||
HttpSessionBindingEvent e = new HttpSessionBindingEvent(this, s, old);
|
||||
attr_listener.attributeReplaced(e);
|
||||
} else {
|
||||
HttpSessionBindingEvent e = new HttpSessionBindingEvent(this, s, o);
|
||||
attr_listener.attributeAdded(e);
|
||||
}
|
||||
}
|
||||
|
||||
@Deprecated
|
||||
@Override
|
||||
public void putValue(String s, Object o)
|
||||
{
|
||||
setAttribute(s,o);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void removeAttribute(String s)
|
||||
{
|
||||
Object o;
|
||||
|
||||
synchronized (attributes) {
|
||||
o = attributes.remove(s);
|
||||
}
|
||||
|
||||
if (o != null && o instanceof HttpSessionBindingListener) {
|
||||
HttpSessionBindingListener l = (HttpSessionBindingListener) o;
|
||||
HttpSessionBindingEvent e = new HttpSessionBindingEvent(this, s);
|
||||
|
||||
l.valueUnbound(e);
|
||||
}
|
||||
|
||||
if (attr_listener == null || o == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
HttpSessionBindingEvent e = new HttpSessionBindingEvent(this, s, o);
|
||||
attr_listener.attributeRemoved(e);
|
||||
}
|
||||
|
||||
@Deprecated
|
||||
@Override
|
||||
public void removeValue(String s)
|
||||
{
|
||||
removeAttribute(s);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void invalidate()
|
||||
{
|
||||
context.invalidateSession(this);
|
||||
|
||||
unboundAttributes();
|
||||
}
|
||||
|
||||
private void unboundAttributes()
|
||||
{
|
||||
for (Map.Entry<String, Object> a : attributes.entrySet()) {
|
||||
Object o = a.getValue();
|
||||
if (o != null && o instanceof HttpSessionBindingListener) {
|
||||
HttpSessionBindingListener l = (HttpSessionBindingListener) o;
|
||||
HttpSessionBindingEvent e = new HttpSessionBindingEvent(this, a.getKey());
|
||||
|
||||
l.valueUnbound(e);
|
||||
}
|
||||
}
|
||||
|
||||
attributes.clear();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isNew()
|
||||
{
|
||||
return is_new;
|
||||
}
|
||||
|
||||
public void accessed() {
|
||||
synchronized (this) {
|
||||
is_new = false;
|
||||
|
||||
last_access_time = access_time;
|
||||
access_time = new Date().getTime();
|
||||
}
|
||||
}
|
||||
|
||||
public boolean checkTimeOut()
|
||||
{
|
||||
return (max_inactive_interval > 0) &&
|
||||
(access_time - last_access_time > max_inactive_interval * 1000);
|
||||
}
|
||||
}
|
||||
40
src/java/nginx/unit/SessionAttrProxy.java
Normal file
40
src/java/nginx/unit/SessionAttrProxy.java
Normal file
@@ -0,0 +1,40 @@
|
||||
package nginx.unit;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import javax.servlet.http.HttpSessionAttributeListener;
|
||||
import javax.servlet.http.HttpSessionBindingEvent;
|
||||
|
||||
public class SessionAttrProxy implements HttpSessionAttributeListener
|
||||
{
|
||||
private final List<HttpSessionAttributeListener> listeners_;
|
||||
|
||||
public SessionAttrProxy(List<HttpSessionAttributeListener> listeners)
|
||||
{
|
||||
listeners_ = listeners;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void attributeAdded(HttpSessionBindingEvent event)
|
||||
{
|
||||
for (HttpSessionAttributeListener l : listeners_) {
|
||||
l.attributeAdded(event);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void attributeRemoved(HttpSessionBindingEvent event)
|
||||
{
|
||||
for (HttpSessionAttributeListener l : listeners_) {
|
||||
l.attributeRemoved(event);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void attributeReplaced(HttpSessionBindingEvent event)
|
||||
{
|
||||
for (HttpSessionAttributeListener l : listeners_) {
|
||||
l.attributeReplaced(event);
|
||||
}
|
||||
}
|
||||
}
|
||||
44
src/java/nginx/unit/Taglib.java
Normal file
44
src/java/nginx/unit/Taglib.java
Normal file
@@ -0,0 +1,44 @@
|
||||
package nginx.unit;
|
||||
|
||||
import javax.servlet.descriptor.TaglibDescriptor;
|
||||
|
||||
import org.w3c.dom.Node;
|
||||
import org.w3c.dom.NodeList;
|
||||
|
||||
public class Taglib implements TaglibDescriptor
|
||||
{
|
||||
private String uri_ = null;
|
||||
private String location_ = null;
|
||||
|
||||
public Taglib(NodeList nodes)
|
||||
{
|
||||
for (int i = 0; i < nodes.getLength(); i++) {
|
||||
Node node = nodes.item(i);
|
||||
String tag_name = node.getNodeName();
|
||||
|
||||
if (tag_name.equals("taglib-uri")) {
|
||||
uri_ = node.getTextContent().trim();
|
||||
continue;
|
||||
}
|
||||
|
||||
if (tag_name.equals("taglib-location")) {
|
||||
location_ = node.getTextContent().trim();
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getTaglibURI()
|
||||
{
|
||||
return uri_;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getTaglibLocation()
|
||||
{
|
||||
return location_;
|
||||
}
|
||||
}
|
||||
|
||||
110
src/java/nginx/unit/UnitSessionCookieConfig.java
Normal file
110
src/java/nginx/unit/UnitSessionCookieConfig.java
Normal file
@@ -0,0 +1,110 @@
|
||||
package nginx.unit;
|
||||
|
||||
import javax.servlet.SessionCookieConfig;
|
||||
|
||||
/*
|
||||
|
||||
<session-config>
|
||||
<session-timeout>60</session-timeout>
|
||||
<cookie-config></cookie-config>
|
||||
<tracking-mode></tracking-mode>
|
||||
</session-config>
|
||||
|
||||
|
||||
*/
|
||||
public class UnitSessionCookieConfig implements SessionCookieConfig {
|
||||
|
||||
private static final String default_name = "JSESSIONID";
|
||||
|
||||
private String name = default_name;
|
||||
private String domain;
|
||||
private String path;
|
||||
private String comment;
|
||||
private boolean httpOnly = true;
|
||||
private boolean secure = false;
|
||||
private int maxAge = -1;
|
||||
|
||||
@Override
|
||||
public void setName(String name)
|
||||
{
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getName()
|
||||
{
|
||||
return name;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setDomain(String domain)
|
||||
{
|
||||
this.domain = domain;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getDomain()
|
||||
{
|
||||
return domain;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setPath(String path)
|
||||
{
|
||||
this.path = path;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getPath()
|
||||
{
|
||||
return path;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setComment(String comment)
|
||||
{
|
||||
this.comment = comment;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getComment()
|
||||
{
|
||||
return comment;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setHttpOnly(boolean httpOnly)
|
||||
{
|
||||
this.httpOnly = httpOnly;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isHttpOnly()
|
||||
{
|
||||
return httpOnly;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setSecure(boolean secure)
|
||||
{
|
||||
this.secure = secure;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isSecure()
|
||||
{
|
||||
return secure;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setMaxAge(int maxAge)
|
||||
{
|
||||
this.maxAge = maxAge;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getMaxAge()
|
||||
{
|
||||
return maxAge;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user