Introducing Java Servlet Container beta.

This commit is contained in:
Max Romanov
2019-02-28 18:02:42 +03:00
parent ec7319d32c
commit 5bfdebb9e4
95 changed files with 13360 additions and 1 deletions

View File

@@ -29,6 +29,10 @@ case "$nxt_module" in
. auto/modules/nodejs
;;
java)
. auto/modules/java
;;
*)
echo
echo $0: error: invalid module \"$nxt_module\".

458
auto/modules/java Normal file
View File

@@ -0,0 +1,458 @@
# Copyright (C) NGINX, Inc.
shift
NXT_JAVA_HOME=${JAVA_HOME-}
NXT_JAR_REPO=http://central.maven.org/maven2/
NXT_JAR_LOCAL_REPO=$HOME/.m2/repository/
for nxt_option; do
case "$nxt_option" in
-*=*) value=`echo "$nxt_option" | sed -e 's/[-_a-zA-Z0-9]*=//'` ;;
*) value="" ;;
esac
case "$nxt_option" in
--module=*) NXT_JAVA_MODULE="$value" ;;
--home=*) NXT_JAVA_HOME="$value" ;;
--lib-path=*) NXT_JAVA_LIB_PATH="$value" ;;
--repo=*) NXT_JAR_REPO="$value" ;;
--local-repo=*) NXT_JAR_LOCAL_REPO="$value" ;;
--jars=*) NXT_JARS="$value" ;;
--help)
cat << END
--module=NAME set unit Java module name
--home=DIR set Java home directory
--lib-path=DIRECTORY set directory path to libjvm.so library
--repo=URL set Maven remote repository URL
default: "$NXT_JAR_REPO"
--local-repo=DIR set local repository directory
default: "$NXT_JAR_LOCAL_REPO"
--jars=DIR set jars install/search directory
END
exit 0
;;
*)
echo
echo $0: error: invalid Java option \"$nxt_option\"
echo
exit 1
;;
esac
done
if [ ! -f $NXT_AUTOCONF_DATA ]; then
echo
echo Please run common $0 before configuring module \"$nxt_module\".
echo
exit 1
fi
. $NXT_AUTOCONF_DATA
NXT_JARS=${NXT_JARS=$NXT_MODULES}
NXT_JAVA_MODULE=${NXT_JAVA_MODULE=java}
NXT_JAVA_LIB_PATH=${NXT_JAVA_LIB_PATH=}
$echo "configuring Java module"
$echo "configuring Java module ..." >> $NXT_AUTOCONF_ERR
if [ -n "${NXT_JAVA_HOME}" ]; then
$echo "using java.home ${NXT_JAVA_HOME}"
$echo "using java.home ${NXT_JAVA_HOME}" >> $NXT_AUTOCONF_ERR
if [ ! -d "${NXT_JAVA_HOME}" ]; then
$echo
$echo $0: error: Java home directory not found.
$echo
exit 1
fi
NXT_JAVA="${NXT_JAVA_HOME}/bin/java"
else
$echo -n "checking for java executable"
$echo "checking for java executable ..." >> $NXT_AUTOCONF_ERR
NXT_JAVA=`which java || :`
if [ -z "$NXT_JAVA" -o ! -x "$NXT_JAVA" ]; then
$echo
$echo $0: error: java executable not found.
$echo
exit 1
fi
$echo " found $NXT_JAVA"
$echo "found $NXT_JAVA" >> $NXT_AUTOCONF_ERR
"$NXT_JAVA" -version
$echo -n "checking java.home"
$echo "checking java.home ..." >> $NXT_AUTOCONF_ERR
NXT_JAVA_HOME=`$NXT_JAVA -XshowSettings 2>&1 | grep -F -e java.home | sed -e 's/^.*= //'`
if [ -z "$NXT_JAVA_HOME" ]; then
$echo
$echo $0: error: java.home not found.
$echo
exit 1
fi
$echo " $NXT_JAVA_HOME"
$echo "got java.home $NXT_JAVA_HOME" >> $NXT_AUTOCONF_ERR
if [ ! -x "${NXT_JAVA_HOME}/bin/javac" ]; then
NXT_JAVA_HOME_=${NXT_JAVA_HOME%/jre}
if [ -x "${NXT_JAVA_HOME_}/bin/javac" ]; then
$echo "adjust java.home $NXT_JAVA_HOME_"
$echo "adjust java.home $NXT_JAVA_HOME_" >> $NXT_AUTOCONF_ERR
NXT_JAVA_HOME="$NXT_JAVA_HOME_"
fi
fi
fi
NXT_JAVAC="${NXT_JAVA_HOME}/bin/javac"
if [ ! -x "$NXT_JAVAC" ]; then
$echo
$echo $0: error: javac not found.
$echo
exit 1
fi
NXT_JAVA_INCLUDE="-I${NXT_JAVA_HOME}/include"
case "$NXT_SYSTEM" in
Linux)
NXT_JAVA_INCLUDE="${NXT_JAVA_INCLUDE} -I${NXT_JAVA_HOME}/include/linux"
;;
Darwin)
NXT_JAVA_INCLUDE="${NXT_JAVA_INCLUDE} -I${NXT_JAVA_HOME}/include/darwin"
;;
FreeBSD)
NXT_JAVA_INCLUDE="${NXT_JAVA_INCLUDE} -I${NXT_JAVA_HOME}/include/freebsd"
;;
esac
if [ -z "$NXT_JAVA_LIB_PATH" ]; then
$echo -n "checking library path"
$echo "checking library path ..." >> $NXT_AUTOCONF_ERR
if [ ! -x "$NXT_JAVA" ]; then
$echo
$echo $0: error: java executable not found.
$echo
exit 1
fi
NXT_JAVA_LIB_PATH=`$NXT_JAVA -XshowSettings 2>&1 | grep -F -e sun.boot.library.path | sed -e 's/^.*= //'`
if [ -z "$NXT_JAVA_LIB_PATH" ]; then
$echo
$echo $0: error: library path not found.
$echo
exit 1
fi
NXT_JAVA_LIB_PATH="${NXT_JAVA_LIB_PATH}/server"
$echo " $NXT_JAVA_LIB_PATH"
$echo "got library path $NXT_JAVA_LIB_PATH" >> $NXT_AUTOCONF_ERR
fi
NXT_JAVA_LDFLAGS="-L${NXT_JAVA_LIB_PATH} -Wl,-rpath ${NXT_JAVA_LIB_PATH} -ljvm"
nxt_found=no
nxt_feature="JNI"
nxt_feature_name=""
nxt_feature_run=no
nxt_feature_incs="${NXT_JAVA_INCLUDE}"
nxt_feature_libs="${NXT_JAVA_LDFLAGS}"
nxt_feature_test="
#include <jni.h>
int main() {
JNI_CreateJavaVM(NULL, NULL, NULL);
return 0;
}"
. auto/feature
if [ $nxt_found = no ]; then
$echo
$echo $0: error: no JNI found.
$echo
exit 1;
fi
NXT_JAVA_VERSION=`$NXT_JAVAC -version 2>&1`
NXT_JAVA_VERSION=${NXT_JAVA_VERSION#javac }
NXT_JAVA_INCLUDE="$NXT_JAVA_INCLUDE -I$NXT_BUILD_DIR/$NXT_JAVA_MODULE -DNXT_JAVA_VERSION=$NXT_JAVA_VERSION"
if grep ^$NXT_JAVA_MODULE: $NXT_MAKEFILE 2>&1 > /dev/null; then
$echo
$echo $0: error: duplicate \"$NXT_JAVA_MODULE\" module configured.
$echo
exit 1;
fi
. ./version
NXT_UNIT_JAR=nginx-unit-jsc-${NXT_JAVA_MODULE}-$NXT_VERSION.jar
NXT_JAVA_BUILD_CP=$NXT_BUILD_DIR/$NXT_JAVA_MODULE
NXT_JAVA_INSTALL_JARS=
NXT_JAVA_UNINSTALL_JARS=
NXT_JAVA_JARS=$NXT_BUILD_DIR/$NXT_JAVA_MODULE/nxt_jars.h
mkdir -p $NXT_BUILD_DIR/$NXT_JAVA_MODULE
cat << END > $NXT_JAVA_JARS
#ifndef _NXT_JAVA_JARS_INCLUDED_
#define _NXT_JAVA_JARS_INCLUDED_
#define NXT_JARS "$NXT_JARS"
static const char *nxt_java_system_jars[] = {
END
NXT_TOMCAT_VERSION=9.0.13
NXT_JAR_VERSION=$NXT_TOMCAT_VERSION
NXT_JAR_NAME=tomcat-servlet-api
NXT_JAR_NAMESPACE=org/apache/tomcat/
. auto/modules/java_get_jar
NXT_JAR_NAME=tomcat-el-api
. auto/modules/java_get_jar
NXT_JAR_NAME=tomcat-jsp-api
. auto/modules/java_get_jar
NXT_JAR_NAME=tomcat-jasper
. auto/modules/java_get_jar
NXT_JAR_NAME=tomcat-jasper-el
. auto/modules/java_get_jar
NXT_JAR_NAME=tomcat-juli
. auto/modules/java_get_jar
NXT_JAR_NAME=tomcat-api
. auto/modules/java_get_jar
NXT_JAR_NAME=tomcat-util-scan
. auto/modules/java_get_jar
NXT_JAR_NAME=tomcat-util
. auto/modules/java_get_jar
NXT_JAR_NAME=ecj
NXT_JAR_VERSION=3.13.102
NXT_JAR_NAMESPACE=org/eclipse/jdt/
. auto/modules/java_get_jar
cat << END >> $NXT_JAVA_JARS
NULL
};
static const char *nxt_java_unit_jars[] = {
"$NXT_UNIT_JAR",
END
NXT_JAR_VERSION=9.4.12.v20180830
NXT_JAR_NAMESPACE=org/eclipse/jetty/
NXT_JAR_NAME=jetty-util
. auto/modules/java_get_jar
NXT_JAR_NAME=jetty-server
. auto/modules/java_get_jar
NXT_JAR_NAME=jetty-http
. auto/modules/java_get_jar
NXT_JAR_NAME=classgraph
NXT_JAR_VERSION=4.4.11
NXT_JAR_NAMESPACE=io/github/classgraph/
. auto/modules/java_get_jar
cat << END >> $NXT_JAVA_JARS
NULL
};
#endif /* _NXT_JAVA_JARS_INCLUDED_ */
END
$echo " + Java module: ${NXT_JAVA_MODULE}.unit.so"
. auto/cc/deps
$echo >> $NXT_MAKEFILE
NXT_JAVA_MODULE_SRCS=" \
src/nxt_java.c \
src/java/nxt_jni.c \
src/java/nxt_jni_Context.c \
src/java/nxt_jni_HeaderNamesEnumeration.c \
src/java/nxt_jni_HeadersEnumeration.c \
src/java/nxt_jni_InputStream.c \
src/java/nxt_jni_OutputStream.c \
src/java/nxt_jni_Request.c \
src/java/nxt_jni_Response.c \
src/java/nxt_jni_Thread.c \
src/java/nxt_jni_URLClassLoader.c \
"
# The Java module object files.
nxt_objs=$NXT_BUILD_DIR/src/nxt_unit.o
for nxt_src in $NXT_JAVA_MODULE_SRCS; do
nxt_obj=${nxt_src%.c}-$NXT_JAVA_MODULE.o
nxt_dep=${nxt_src%.c}-$NXT_JAVA_MODULE.dep
nxt_dep_flags=`nxt_gen_dep_flags`
nxt_dep_post=`nxt_gen_dep_post`
nxt_objs="$nxt_objs $NXT_BUILD_DIR/$nxt_obj"
cat << END >> $NXT_MAKEFILE
$NXT_BUILD_DIR/$nxt_obj: $nxt_src
mkdir -p $NXT_BUILD_DIR/src/java
\$(CC) -c \$(CFLAGS) \$(NXT_INCS) $NXT_JAVA_INCLUDE \\
$nxt_dep_flags \\
-o $NXT_BUILD_DIR/$nxt_obj $nxt_src
$nxt_dep_post
-include $NXT_BUILD_DIR/$nxt_dep
END
done
NXT_JAVA_SRCS=" \
src/java/nginx/unit/Context.java \
src/java/nginx/unit/DynamicDispatcherRequest.java \
src/java/nginx/unit/DynamicPathRequest.java \
src/java/nginx/unit/ForwardRequestWrapper.java \
src/java/nginx/unit/HeaderNamesEnumeration.java \
src/java/nginx/unit/HeadersEnumeration.java \
src/java/nginx/unit/IncludeRequestWrapper.java \
src/java/nginx/unit/IncludeResponseWrapper.java \
src/java/nginx/unit/InitParams.java \
src/java/nginx/unit/InputStream.java \
src/java/nginx/unit/JspPropertyGroup.java \
src/java/nginx/unit/OutputStream.java \
src/java/nginx/unit/Request.java \
src/java/nginx/unit/RequestAttrProxy.java \
src/java/nginx/unit/Response.java \
src/java/nginx/unit/Session.java \
src/java/nginx/unit/SessionAttrProxy.java \
src/java/nginx/unit/Taglib.java \
src/java/nginx/unit/UnitSessionCookieConfig.java \
"
cat << END >> $NXT_MAKEFILE
.PHONY: ${NXT_JAVA_MODULE}
.PHONY: ${NXT_JAVA_MODULE}-install
.PHONY: ${NXT_JAVA_MODULE}-uninstall
all: ${NXT_JAVA_MODULE}
${NXT_JAVA_MODULE}: $NXT_BUILD_DIR/${NXT_JAVA_MODULE}.unit.so \
$NXT_BUILD_DIR/$NXT_UNIT_JAR
$NXT_BUILD_DIR/${NXT_JAVA_MODULE}.unit.so: $nxt_objs
\$(NXT_MODULE_LINK) -o $NXT_BUILD_DIR/${NXT_JAVA_MODULE}.unit.so \\
$nxt_objs $NXT_JAVA_LDFLAGS $NXT_LD_OPT
install: ${NXT_JAVA_MODULE}-install
${NXT_JAVA_MODULE}-install: $NXT_BUILD_DIR/${NXT_JAVA_MODULE}.unit.so \\
$NXT_BUILD_DIR/$NXT_UNIT_JAR java-shared-install
install -d \$(DESTDIR)$NXT_MODULES
install -p $NXT_BUILD_DIR/${NXT_JAVA_MODULE}.unit.so \\
\$(DESTDIR)$NXT_MODULES/
install -d \$(DESTDIR)$NXT_JARS
install -p -m 0644 $NXT_BUILD_DIR/$NXT_UNIT_JAR \$(DESTDIR)$NXT_JARS/
uninstall: ${NXT_JAVA_MODULE}-uninstall
${NXT_JAVA_MODULE}-uninstall: java-shared-uninstall
rm -f \$(DESTDIR)$NXT_MODULES/${NXT_JAVA_MODULE}.unit.so
@rmdir -p \$(DESTDIR)$NXT_MODULES 2>/dev/null || true
rm -f \$(DESTDIR)$NXT_JARS/$NXT_UNIT_JAR
@rmdir -p \$(DESTDIR)$NXT_JARS 2>/dev/null || true
END
if ! grep ^$NXT_BUILD_DIR/$NXT_UNIT_JAR: $NXT_MAKEFILE 2>&1 > /dev/null; then
cat << END >> $NXT_MAKEFILE
.INTERMEDIATE: $NXT_BUILD_DIR/$NXT_JAVA_MODULE/.classes
NXT_JAVA_SRCS = $NXT_JAVA_SRCS
$NXT_BUILD_DIR/$NXT_JAVA_MODULE/.classes: \$(NXT_JAVA_SRCS)
rm -rf $NXT_BUILD_DIR/$NXT_JAVA_MODULE/nginx
$NXT_JAVAC -d $NXT_BUILD_DIR/$NXT_JAVA_MODULE -cp $NXT_JAVA_BUILD_CP \\
\$(NXT_JAVA_SRCS)
$NXT_BUILD_DIR/$NXT_JAVA_MODULE/META-INF/LICENSE: LICENSE
mkdir -p $NXT_BUILD_DIR/$NXT_JAVA_MODULE/META-INF
cp -p LICENSE \$@
$NXT_BUILD_DIR/$NXT_JAVA_MODULE/META-INF/NOTICE: NOTICE
mkdir -p $NXT_BUILD_DIR/$NXT_JAVA_MODULE/META-INF
cp -p NOTICE \$@
$NXT_BUILD_DIR/$NXT_UNIT_JAR: $NXT_BUILD_DIR/$NXT_JAVA_MODULE/.classes \\
$NXT_BUILD_DIR/$NXT_JAVA_MODULE/META-INF/LICENSE \\
$NXT_BUILD_DIR/$NXT_JAVA_MODULE/META-INF/NOTICE
$NXT_JAVA_HOME/bin/jar c -C $NXT_BUILD_DIR/$NXT_JAVA_MODULE META-INF \\
-C $NXT_BUILD_DIR/$NXT_JAVA_MODULE nginx/unit > \$@
END
fi
if ! grep ^java-shared-install: $NXT_MAKEFILE 2>&1 > /dev/null; then
cat << END >> $NXT_MAKEFILE
.PHONY: java-shared-install
.PHONY: java-shared-uninstall
java-shared-install: $NXT_JAVA_INSTALL_JARS
install -d \$(DESTDIR)$NXT_JARS
install -p -m 0644 $NXT_JAVA_INSTALL_JARS \$(DESTDIR)$NXT_JARS/
java-shared-uninstall:
rm -f $NXT_JAVA_UNINSTALL_JARS
@rmdir -p \$(DESTDIR)$NXT_JARS 2>/dev/null || true
END
fi

33
auto/modules/java_get_jar Normal file
View File

@@ -0,0 +1,33 @@
# Copyright (C) NGINX, Inc.
# NXT_JAR_NAME=
# NXT_JAR_VERSION=
# NXT_JAR_NAMESPACE=
# NXT_JAR_REPO=http://central.maven.org/maven2/
# NXT_JAR_LOCAL_REPO=$HOME/.m2/repository/
NXT_JAR_FILE=${NXT_JAR_NAME}-${NXT_JAR_VERSION}.jar
NXT_JAR_LOCAL="${NXT_JAR_LOCAL_REPO}${NXT_JAR_NAMESPACE}${NXT_JAR_NAME}/${NXT_JAR_VERSION}/${NXT_JAR_FILE}"
NXT_JAR_URL=${NXT_JAR_REPO}${NXT_JAR_NAMESPACE}${NXT_JAR_NAME}/${NXT_JAR_VERSION}/${NXT_JAR_FILE}
if [ ! -f "$NXT_BUILD_DIR/$NXT_JAR_FILE" ]; then
if [ ! -f "$NXT_JAR_LOCAL" ]; then
$echo "getting remote $NXT_JAR_FILE ... "
$echo "getting remote $NXT_JAR_FILE ..." >> $NXT_AUTOCONF_ERR
mkdir -p "${NXT_JAR_LOCAL_REPO}${NXT_JAR_NAMESPACE}${NXT_JAR_NAME}/${NXT_JAR_VERSION}/"
curl --progress-bar "$NXT_JAR_URL" -o "$NXT_JAR_LOCAL"
else
$echo "getting local $NXT_JAR_FILE"
$echo "getting local $NXT_JAR_FILE ..." >> $NXT_AUTOCONF_ERR
fi
cp "$NXT_JAR_LOCAL" "$NXT_BUILD_DIR/$NXT_JAR_FILE"
fi
NXT_JAVA_BUILD_CP="${NXT_JAVA_BUILD_CP}:$NXT_BUILD_DIR/$NXT_JAR_FILE"
NXT_JAVA_INSTALL_JARS="$NXT_JAVA_INSTALL_JARS $NXT_BUILD_DIR/$NXT_JAR_FILE"
NXT_JAVA_UNINSTALL_JARS="$NXT_JAVA_UNINSTALL_JARS \$(DESTDIR)$NXT_JARS/$NXT_JAR_FILE"
$echo " \"$NXT_JAR_FILE\"," >> $NXT_JAVA_JARS

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,8 @@
package nginx.unit;
import javax.servlet.DispatcherType;
public interface DynamicDispatcherRequest
{
public void setDispatcherType(DispatcherType type);
}

View 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();
}

View 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);
}
}

View 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);
}

View 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);
}

View 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);
}
}

View 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));
}
}

View File

@@ -0,0 +1,7 @@
package nginx.unit;
public interface InitParams {
public boolean setInitParameter(String name, String value);
public String getInitParameter(String name);
}

View 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);
}

View 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_;
}
}

View 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)
{
}
}

File diff suppressed because it is too large Load Diff

View 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);
}
}
}

View 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);
}

View 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);
}
}

View 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);
}
}
}

View 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_;
}
}

View 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;
}
}

175
src/java/nxt_jni.c Normal file
View File

@@ -0,0 +1,175 @@
/*
* Copyright (C) NGINX, Inc.
*/
#include <nxt_auto_config.h>
#include <jni.h>
#include <nxt_unit.h>
#include <nxt_unit_field.h>
#include "nxt_jni.h"
static jclass nxt_java_NoSuchElementException_class;
static jclass nxt_java_IOException_class;
static jclass nxt_java_IllegalStateException_class;
static jclass nxt_java_File_class;
static jmethodID nxt_java_File_ctor;
static inline char nxt_java_lowcase(char c);
int
nxt_java_jni_init(JNIEnv *env)
{
jclass cls;
cls = (*env)->FindClass(env, "java/util/NoSuchElementException");
if (cls == NULL) {
return NXT_UNIT_ERROR;
}
nxt_java_NoSuchElementException_class = (*env)->NewGlobalRef(env, cls);
(*env)->DeleteLocalRef(env, cls);
cls = (*env)->FindClass(env, "java/io/IOException");
if (cls == NULL) {
(*env)->DeleteGlobalRef(env, nxt_java_NoSuchElementException_class);
return NXT_UNIT_ERROR;
}
nxt_java_IOException_class = (*env)->NewGlobalRef(env, cls);
(*env)->DeleteLocalRef(env, cls);
cls = (*env)->FindClass(env, "java/lang/IllegalStateException");
if (cls == NULL) {
(*env)->DeleteGlobalRef(env, nxt_java_NoSuchElementException_class);
(*env)->DeleteGlobalRef(env, nxt_java_IOException_class);
return NXT_UNIT_ERROR;
}
nxt_java_IllegalStateException_class = (*env)->NewGlobalRef(env, cls);
(*env)->DeleteLocalRef(env, cls);
cls = (*env)->FindClass(env, "java/io/File");
if (cls == NULL) {
(*env)->DeleteGlobalRef(env, nxt_java_NoSuchElementException_class);
(*env)->DeleteGlobalRef(env, nxt_java_IOException_class);
(*env)->DeleteGlobalRef(env, nxt_java_IllegalStateException_class);
return NXT_UNIT_ERROR;
}
nxt_java_File_class = (*env)->NewGlobalRef(env, cls);
(*env)->DeleteLocalRef(env, cls);
nxt_java_File_ctor = (*env)->GetMethodID(env, nxt_java_File_class, "<init>",
"(Ljava/lang/String;)V");
if (nxt_java_File_ctor == NULL) {
(*env)->DeleteGlobalRef(env, nxt_java_NoSuchElementException_class);
(*env)->DeleteGlobalRef(env, nxt_java_IOException_class);
(*env)->DeleteGlobalRef(env, nxt_java_IllegalStateException_class);
(*env)->DeleteGlobalRef(env, nxt_java_File_class);
return NXT_UNIT_ERROR;
}
return NXT_UNIT_OK;
}
void
nxt_java_throw_NoSuchElementException(JNIEnv *env, const char *msg)
{
(*env)->ThrowNew(env, nxt_java_NoSuchElementException_class, msg);
}
void
nxt_java_throw_IOException(JNIEnv *env, const char *msg)
{
(*env)->ThrowNew(env, nxt_java_IOException_class, msg);
}
void
nxt_java_throw_IllegalStateException(JNIEnv *env, const char *msg)
{
(*env)->ThrowNew(env, nxt_java_IllegalStateException_class, msg);
}
nxt_unit_field_t *
nxt_java_findHeader(nxt_unit_field_t *f, nxt_unit_field_t *end,
const char *name, uint8_t name_len)
{
const char *field_name;
for (/* void */ ; f < end; f++) {
if (f->skip != 0 || f->name_length != name_len) {
continue;
}
field_name = nxt_unit_sptr_get(&f->name);
if (nxt_java_strcaseeq(name, field_name, name_len)) {
return f;
}
}
return NULL;
}
int
nxt_java_strcaseeq(const char *str1, const char *str2, int len)
{
char c1, c2;
const char *end1;
end1 = str1 + len;
while (str1 < end1) {
c1 = nxt_java_lowcase(*str1++);
c2 = nxt_java_lowcase(*str2++);
if (c1 != c2) {
return 0;
}
}
return 1;
}
static inline char
nxt_java_lowcase(char c)
{
return (c >= 'A' && c <= 'Z') ? c | 0x20 : c;
}
jstring
nxt_java_newString(JNIEnv *env, char *str, uint32_t len)
{
char tmp;
jstring res;
tmp = str[len];
if (tmp != '\0') {
str[len] = '\0';
}
res = (*env)->NewStringUTF(env, str);
if (tmp != '\0') {
str[len] = tmp;
}
return res;
}

55
src/java/nxt_jni.h Normal file
View File

@@ -0,0 +1,55 @@
/*
* Copyright (C) NGINX, Inc.
*/
#ifndef _NXT_JAVA_JNI_H_INCLUDED_
#define _NXT_JAVA_JNI_H_INCLUDED_
#include <jni.h>
#include <nxt_unit_typedefs.h>
int nxt_java_jni_init(JNIEnv *env);
void nxt_java_throw_NoSuchElementException(JNIEnv *env, const char *msg);
void nxt_java_throw_IOException(JNIEnv *env, const char *msg);
void nxt_java_throw_IllegalStateException(JNIEnv *env, const char *msg);
nxt_unit_field_t *nxt_java_findHeader(nxt_unit_field_t *f, nxt_unit_field_t *e,
const char *name, uint8_t name_len);
int nxt_java_strcaseeq(const char *str1, const char *str2, int len);
jstring nxt_java_newString(JNIEnv *env, char *str, uint32_t len);
typedef struct {
uint32_t header_size;
uint32_t buf_size;
jobject jreq;
jobject jresp;
nxt_unit_buf_t *first;
nxt_unit_buf_t *buf;
} nxt_java_request_data_t;
static inline jlong
nxt_ptr2jlong(void *ptr)
{
return (jlong) (intptr_t) ptr;
}
static inline void *
nxt_jlong2ptr(jlong l)
{
return (void *) (intptr_t) l;
}
#endif /* _NXT_JAVA_JNI_H_INCLUDED_ */

164
src/java/nxt_jni_Context.c Normal file
View File

@@ -0,0 +1,164 @@
/*
* Copyright (C) NGINX, Inc.
*/
#include <nxt_auto_config.h>
#include <nxt_unit.h>
#include <jni.h>
#include "nxt_jni.h"
#include "nxt_jni_Context.h"
#include "nxt_jni_URLClassLoader.h"
static jclass nxt_java_Context_class;
static jmethodID nxt_java_Context_start;
static jmethodID nxt_java_Context_service;
static jmethodID nxt_java_Context_stop;
static void JNICALL nxt_java_Context_log(JNIEnv *env, jclass cls,
jlong ctx_ptr, jstring msg, jint msg_len);
static void JNICALL nxt_java_Context_trace(JNIEnv *env, jclass cls,
jlong ctx_ptr, jstring msg, jint msg_len);
int
nxt_java_initContext(JNIEnv *env, jobject cl)
{
int res;
jclass cls;
cls = nxt_java_loadClass(env, cl, "nginx.unit.Context");
if (cls == NULL) {
nxt_unit_warn(NULL, "nginx.unit.Context not found");
return NXT_UNIT_ERROR;
}
nxt_java_Context_class = (*env)->NewGlobalRef(env, cls);
(*env)->DeleteLocalRef(env, cls);
cls = nxt_java_Context_class;
nxt_java_Context_start = (*env)->GetStaticMethodID(env, cls, "start",
"(Ljava/lang/String;[Ljava/net/URL;)Lnginx/unit/Context;");
if (nxt_java_Context_start == NULL) {
nxt_unit_warn(NULL, "nginx.unit.Context.start() not found");
goto failed;
}
nxt_java_Context_service = (*env)->GetMethodID(env, cls, "service",
"(Lnginx/unit/Request;Lnginx/unit/Response;)V");
if (nxt_java_Context_service == NULL) {
nxt_unit_warn(NULL, "nginx.unit.Context.service() not found");
goto failed;
}
nxt_java_Context_stop = (*env)->GetMethodID(env, cls, "stop", "()V");
if (nxt_java_Context_service == NULL) {
nxt_unit_warn(NULL, "nginx.unit.Context.stop() not found");
goto failed;
}
JNINativeMethod context_methods[] = {
{ (char *) "log",
(char *) "(JLjava/lang/String;I)V",
nxt_java_Context_log },
{ (char *) "trace",
(char *) "(JLjava/lang/String;I)V",
nxt_java_Context_trace },
};
res = (*env)->RegisterNatives(env, nxt_java_Context_class,
context_methods,
sizeof(context_methods)
/ sizeof(context_methods[0]));
nxt_unit_debug(NULL, "registered Context methods: %d", res);
if (res != 0) {
nxt_unit_warn(NULL, "registering natives for Context failed");
goto failed;
}
return NXT_UNIT_OK;
failed:
(*env)->DeleteGlobalRef(env, cls);
return NXT_UNIT_ERROR;
}
jobject
nxt_java_startContext(JNIEnv *env, const char *webapp, jobject classpaths)
{
jstring webapp_str;
webapp_str = (*env)->NewStringUTF(env, webapp);
if (webapp_str == NULL) {
return NULL;
}
return (*env)->CallStaticObjectMethod(env, nxt_java_Context_class,
nxt_java_Context_start, webapp_str,
classpaths);
}
void
nxt_java_service(JNIEnv *env, jobject ctx, jobject jreq, jobject jresp)
{
(*env)->CallVoidMethod(env, ctx, nxt_java_Context_service, jreq, jresp);
}
void
nxt_java_stopContext(JNIEnv *env, jobject ctx)
{
(*env)->CallVoidMethod(env, ctx, nxt_java_Context_stop);
}
static void JNICALL
nxt_java_Context_log(JNIEnv *env, jclass cls, jlong ctx_ptr, jstring msg,
jint msg_len)
{
const char *msg_str;
nxt_unit_ctx_t *ctx;
ctx = nxt_jlong2ptr(ctx_ptr);
msg_str = (*env)->GetStringUTFChars(env, msg, NULL);
if (msg_str == NULL) {
return;
}
nxt_unit_log(ctx, NXT_UNIT_LOG_INFO, "%.*s", msg_len, msg_str);
(*env)->ReleaseStringUTFChars(env, msg, msg_str);
}
static void JNICALL
nxt_java_Context_trace(JNIEnv *env, jclass cls, jlong ctx_ptr, jstring msg,
jint msg_len)
{
#if (NXT_DEBUG)
const char *msg_str;
nxt_unit_ctx_t *ctx;
ctx = nxt_jlong2ptr(ctx_ptr);
msg_str = (*env)->GetStringUTFChars(env, msg, NULL);
if (msg_str == NULL) {
return;
}
nxt_unit_debug(ctx, "%.*s", msg_len, msg_str);
(*env)->ReleaseStringUTFChars(env, msg, msg_str);
#endif
}

View File

@@ -0,0 +1,23 @@
/*
* Copyright (C) NGINX, Inc.
*/
#ifndef _NXT_JAVA_CONTEXT_H_INCLUDED_
#define _NXT_JAVA_CONTEXT_H_INCLUDED_
#include <jni.h>
int nxt_java_initContext(JNIEnv *env, jobject cl);
jobject nxt_java_startContext(JNIEnv *env, const char *webapp,
jobject classpaths);
void nxt_java_service(JNIEnv *env, jobject ctx, jobject jreq, jobject jresp);
void nxt_java_stopContext(JNIEnv *env, jobject ctx);
#endif /* _NXT_JAVA_CONTEXT_H_INCLUDED_ */

View File

@@ -0,0 +1,153 @@
/*
* Copyright (C) NGINX, Inc.
*/
#include <nxt_auto_config.h>
#include <nxt_unit.h>
#include <nxt_unit_request.h>
#include <jni.h>
#include <stdio.h>
#include "nxt_jni.h"
#include "nxt_jni_URLClassLoader.h"
#include "nxt_jni_HeaderNamesEnumeration.h"
static jlong JNICALL nxt_java_HeaderNamesEnumeration_nextElementPos(JNIEnv *env,
jclass cls, jlong headers_ptr, jlong size, jlong pos);
static jstring JNICALL nxt_java_HeaderNamesEnumeration_nextElement(JNIEnv *env,
jclass cls, jlong headers_ptr, jlong size, jlong pos);
static jclass nxt_java_HeaderNamesEnumeration_class;
static jmethodID nxt_java_HeaderNamesEnumeration_ctor;
int
nxt_java_initHeaderNamesEnumeration(JNIEnv *env, jobject cl)
{
int res;
jclass cls;
cls = nxt_java_loadClass(env, cl, "nginx.unit.HeaderNamesEnumeration");
if (cls == NULL) {
return NXT_UNIT_ERROR;
}
nxt_java_HeaderNamesEnumeration_class = (*env)->NewGlobalRef(env, cls);
(*env)->DeleteLocalRef(env, cls);
cls = nxt_java_HeaderNamesEnumeration_class;
nxt_java_HeaderNamesEnumeration_ctor = (*env)->GetMethodID(env, cls,
"<init>", "(JJ)V");
if (nxt_java_HeaderNamesEnumeration_ctor == NULL) {
(*env)->DeleteGlobalRef(env, cls);
return NXT_UNIT_ERROR;
}
JNINativeMethod hnenum_methods[] = {
{ (char *) "nextElementPos",
(char *) "(JJJ)J",
nxt_java_HeaderNamesEnumeration_nextElementPos },
{ (char *) "nextElement",
(char *) "(JJJ)Ljava/lang/String;",
nxt_java_HeaderNamesEnumeration_nextElement },
};
res = (*env)->RegisterNatives(env, nxt_java_HeaderNamesEnumeration_class,
hnenum_methods,
sizeof(hnenum_methods)
/ sizeof(hnenum_methods[0]));
nxt_unit_debug(NULL, "registered HeaderNamesEnumeration methods: %d", res);
if (res != 0) {
(*env)->DeleteGlobalRef(env, cls);
return NXT_UNIT_ERROR;
}
return NXT_UNIT_OK;
}
jobject
nxt_java_newHeaderNamesEnumeration(JNIEnv *env, nxt_unit_field_t *f,
uint32_t fields_count)
{
return (*env)->NewObject(env,
nxt_java_HeaderNamesEnumeration_class,
nxt_java_HeaderNamesEnumeration_ctor, nxt_ptr2jlong(f),
(jlong) fields_count);
}
static jlong JNICALL
nxt_java_HeaderNamesEnumeration_nextElementPos(JNIEnv *env, jclass cls,
jlong headers_ptr, jlong size, jlong pos)
{
nxt_unit_field_t *f;
f = nxt_jlong2ptr(headers_ptr);
if (pos >= size) {
return size;
}
if (pos > 0) {
while (pos < size
&& f[pos].hash == f[pos - 1].hash
&& f[pos].name_length == f[pos - 1].name_length)
{
pos++;
}
}
return pos;
}
static jstring JNICALL
nxt_java_HeaderNamesEnumeration_nextElement(JNIEnv *env, jclass cls,
jlong headers_ptr, jlong size, jlong pos)
{
char *name, tmp;
jstring res;
nxt_unit_field_t *f;
f = nxt_jlong2ptr(headers_ptr);
if (pos > 0) {
while (pos < size
&& f[pos].hash == f[pos - 1].hash
&& f[pos].name_length == f[pos - 1].name_length)
{
pos++;
}
}
if (pos >= size) {
nxt_java_throw_NoSuchElementException(env, "pos >= size");
return NULL;
}
f += pos;
name = nxt_unit_sptr_get(&f->name);
tmp = name[f->name_length];
if (tmp != '\0') {
name[f->name_length] = '\0';
}
res = (*env)->NewStringUTF(env, name);
if (tmp != '\0') {
name[f->name_length] = tmp;
}
return res;
}

View File

@@ -0,0 +1,19 @@
/*
* Copyright (C) NGINX, Inc.
*/
#ifndef _NXT_JAVA_HEADERNAMESENUMERATION_H_INCLUDED_
#define _NXT_JAVA_HEADERNAMESENUMERATION_H_INCLUDED_
#include <jni.h>
#include <nxt_unit_typedefs.h>
int nxt_java_initHeaderNamesEnumeration(JNIEnv *env, jobject cl);
jobject nxt_java_newHeaderNamesEnumeration(JNIEnv *env, nxt_unit_field_t *f,
uint32_t fields_count);
#endif /* _NXT_JAVA_HEADERNAMESENUMERATION_H_INCLUDED_ */

View File

@@ -0,0 +1,148 @@
/*
* Copyright (C) NGINX, Inc.
*/
#include <nxt_auto_config.h>
#include <nxt_unit.h>
#include <nxt_unit_request.h>
#include <jni.h>
#include <stdio.h>
#include "nxt_jni.h"
#include "nxt_jni_URLClassLoader.h"
#include "nxt_jni_HeadersEnumeration.h"
static jclass nxt_java_HeadersEnumeration_class;
static jmethodID nxt_java_HeadersEnumeration_ctor;
static jlong JNICALL nxt_java_HeadersEnumeration_nextElementPos(JNIEnv *env,
jclass cls, jlong headers_ptr, jlong size, jlong ipos, jlong pos);
static jstring JNICALL nxt_java_HeadersEnumeration_nextElement(JNIEnv *env,
jclass cls, jlong headers_ptr, jlong size, jlong ipos, jlong pos);
int
nxt_java_initHeadersEnumeration(JNIEnv *env, jobject cl)
{
int res;
jclass cls;
cls = nxt_java_loadClass(env, cl, "nginx.unit.HeadersEnumeration");
if (cls == NULL) {
return NXT_UNIT_ERROR;
}
nxt_java_HeadersEnumeration_class = (*env)->NewGlobalRef(env, cls);
(*env)->DeleteLocalRef(env, cls);
cls = nxt_java_HeadersEnumeration_class;
nxt_java_HeadersEnumeration_ctor = (*env)->GetMethodID(env, cls,
"<init>", "(JJJ)V");
if (nxt_java_HeadersEnumeration_ctor == NULL) {
(*env)->DeleteGlobalRef(env, cls);
return NXT_UNIT_ERROR;
}
JNINativeMethod methods[] = {
{ (char *) "nextElementPos",
(char *) "(JJJJ)J",
nxt_java_HeadersEnumeration_nextElementPos },
{ (char *) "nextElement",
(char *) "(JJJJ)Ljava/lang/String;",
nxt_java_HeadersEnumeration_nextElement },
};
res = (*env)->RegisterNatives(env, nxt_java_HeadersEnumeration_class,
methods,
sizeof(methods) / sizeof(methods[0]));
nxt_unit_debug(NULL, "registered HeadersEnumeration methods: %d", res);
if (res != 0) {
(*env)->DeleteGlobalRef(env, cls);
return NXT_UNIT_ERROR;
}
return NXT_UNIT_OK;
}
jobject
nxt_java_newHeadersEnumeration(JNIEnv *env, nxt_unit_field_t *f,
uint32_t fields_count, uint32_t pos)
{
return (*env)->NewObject(env,
nxt_java_HeadersEnumeration_class,
nxt_java_HeadersEnumeration_ctor, nxt_ptr2jlong(f),
(jlong) fields_count, (jlong) pos);
}
static jlong JNICALL
nxt_java_HeadersEnumeration_nextElementPos(JNIEnv *env, jclass cls,
jlong headers_ptr, jlong size, jlong ipos, jlong pos)
{
nxt_unit_field_t *f, *init_field;
f = nxt_jlong2ptr(headers_ptr);
init_field = f + ipos;
if (pos >= size) {
return size;
}
f += pos;
if (f->hash != init_field->hash
|| f->name_length != init_field->name_length)
{
return size;
}
if (!nxt_java_strcaseeq(nxt_unit_sptr_get(&f->name),
nxt_unit_sptr_get(&init_field->name),
init_field->name_length))
{
return size;
}
return pos;
}
static jstring JNICALL
nxt_java_HeadersEnumeration_nextElement(JNIEnv *env, jclass cls,
jlong headers_ptr, jlong size, jlong ipos, jlong pos)
{
nxt_unit_field_t *f, *init_field;
f = nxt_jlong2ptr(headers_ptr);
init_field = f + ipos;
if (pos >= size) {
nxt_java_throw_IOException(env, "pos >= size");
return NULL;
}
f += pos;
if (f->hash != init_field->hash
|| f->name_length != init_field->name_length)
{
nxt_java_throw_IOException(env, "f->hash != hash");
return NULL;
}
return nxt_java_newString(env, nxt_unit_sptr_get(&f->value),
f->value_length);
}

View File

@@ -0,0 +1,19 @@
/*
* Copyright (C) NGINX, Inc.
*/
#ifndef _NXT_JAVA_HEADERSENUMERATION_H_INCLUDED_
#define _NXT_JAVA_HEADERSENUMERATION_H_INCLUDED_
#include <jni.h>
#include <nxt_unit_typedefs.h>
int nxt_java_initHeadersEnumeration(JNIEnv *env, jobject cl);
jobject nxt_java_newHeadersEnumeration(JNIEnv *env, nxt_unit_field_t *f,
uint32_t fields_count, uint32_t pos);
#endif /* _NXT_JAVA_HEADERSENUMERATION_H_INCLUDED_ */

View File

@@ -0,0 +1,230 @@
/*
* Copyright (C) NGINX, Inc.
*/
#include <nxt_auto_config.h>
#include <jni.h>
#include <nxt_unit.h>
#include <string.h>
#include "nxt_jni.h"
#include "nxt_jni_InputStream.h"
#include "nxt_jni_URLClassLoader.h"
static jint JNICALL nxt_java_InputStream_readLine(JNIEnv *env, jclass cls,
jlong req_info_ptr, jarray b, jint off, jint len);
static jboolean JNICALL nxt_java_InputStream_isFinished(JNIEnv *env, jclass cls,
jlong req_info_ptr);
static jint JNICALL nxt_java_InputStream_readByte(JNIEnv *env, jclass cls,
jlong req_info_ptr);
static jint JNICALL nxt_java_InputStream_read(JNIEnv *env, jclass cls,
jlong req_info_ptr, jarray b, jint off, jint len);
static jlong JNICALL nxt_java_InputStream_skip(JNIEnv *env, jclass cls,
jlong req_info_ptr, jlong n);
static jint JNICALL nxt_java_InputStream_available(JNIEnv *env, jclass cls,
jlong req_info_ptr);
static jclass nxt_java_InputStream_class;
int
nxt_java_initInputStream(JNIEnv *env, jobject cl)
{
int res;
jclass cls;
cls = nxt_java_loadClass(env, cl, "nginx.unit.InputStream");
if (cls == NULL) {
return NXT_UNIT_ERROR;
}
nxt_java_InputStream_class = (*env)->NewGlobalRef(env, cls);
(*env)->DeleteLocalRef(env, cls);
JNINativeMethod is_methods[] = {
{ (char *) "readLine",
(char *) "(J[BII)I",
nxt_java_InputStream_readLine },
{ (char *) "isFinished",
(char *) "(J)Z",
nxt_java_InputStream_isFinished },
{ (char *) "read",
(char *) "(J)I",
nxt_java_InputStream_readByte },
{ (char *) "read",
(char *) "(J[BII)I",
nxt_java_InputStream_read },
{ (char *) "skip",
(char *) "(JJ)J",
nxt_java_InputStream_skip },
{ (char *) "available",
(char *) "(J)I",
nxt_java_InputStream_available },
};
res = (*env)->RegisterNatives(env, nxt_java_InputStream_class,
is_methods,
sizeof(is_methods) / sizeof(is_methods[0]));
nxt_unit_debug(NULL, "registered InputStream methods: %d", res);
if (res != 0) {
(*env)->DeleteGlobalRef(env, cls);
return NXT_UNIT_ERROR;
}
return NXT_UNIT_OK;
}
static jint JNICALL
nxt_java_InputStream_readLine(JNIEnv *env, jclass cls,
jlong req_info_ptr, jarray out, jint off, jint len)
{
char *p;
jint size, b_size;
uint8_t *data;
ssize_t res;
nxt_unit_buf_t *b;
nxt_unit_request_info_t *req;
req = nxt_jlong2ptr(req_info_ptr);
size = 0;
for (b = req->content_buf; b; b = nxt_unit_buf_next(b)) {
b_size = b->end - b->free;
p = memchr(b->free, '\n', b_size);
if (p != NULL) {
p++;
size += p - b->free;
break;
}
size += b_size;
if (size >= len) {
break;
}
}
len = len < size ? len : size;
data = (*env)->GetPrimitiveArrayCritical(env, out, NULL);
res = nxt_unit_request_read(req, data + off, len);
nxt_unit_req_debug(req, "readLine '%.*s'", res, (char *) data + off);
(*env)->ReleasePrimitiveArrayCritical(env, out, data, 0);
return res > 0 ? res : -1;
}
static jboolean JNICALL
nxt_java_InputStream_isFinished(JNIEnv *env, jclass cls, jlong req_info_ptr)
{
nxt_unit_request_info_t *req;
req = nxt_jlong2ptr(req_info_ptr);
return req->content_length == 0;
}
static jint JNICALL
nxt_java_InputStream_readByte(JNIEnv *env, jclass cls, jlong req_info_ptr)
{
uint8_t b;
ssize_t size;
nxt_unit_request_info_t *req;
req = nxt_jlong2ptr(req_info_ptr);
size = nxt_unit_request_read(req, &b, 1);
return size == 1 ? b : -1;
}
static jint JNICALL
nxt_java_InputStream_read(JNIEnv *env, jclass cls, jlong req_info_ptr,
jarray b, jint off, jint len)
{
uint8_t *data;
ssize_t res;
nxt_unit_request_info_t *req;
req = nxt_jlong2ptr(req_info_ptr);
data = (*env)->GetPrimitiveArrayCritical(env, b, NULL);
res = nxt_unit_request_read(req, data + off, len);
nxt_unit_req_debug(req, "read '%.*s'", res, (char *) data + off);
(*env)->ReleasePrimitiveArrayCritical(env, b, data, 0);
return res > 0 ? res : -1;
}
static jlong JNICALL
nxt_java_InputStream_skip(JNIEnv *env, jclass cls, jlong req_info_ptr, jlong n)
{
size_t rest, b_size;
nxt_unit_buf_t *buf;
nxt_unit_request_info_t *req;
req = nxt_jlong2ptr(req_info_ptr);
rest = n;
buf = req->content_buf;
while (buf != NULL) {
b_size = buf->end - buf->free;
b_size = rest < b_size ? rest : b_size;
buf->free += b_size;
rest -= b_size;
if (rest == 0) {
if (buf->end == buf->free) {
buf = nxt_unit_buf_next(buf);
}
break;
}
buf = nxt_unit_buf_next(buf);
}
n = n < (jlong) req->content_length ? n : (jlong) req->content_length;
req->content_length -= n;
return n;
}
static jint JNICALL
nxt_java_InputStream_available(JNIEnv *env, jclass cls, jlong req_info_ptr)
{
nxt_unit_request_info_t *req;
req = nxt_jlong2ptr(req_info_ptr);
return req->content_length;
}

View File

@@ -0,0 +1,15 @@
/*
* Copyright (C) NGINX, Inc.
*/
#ifndef _NXT_JAVA_INPUTSTREAM_H_INCLUDED_
#define _NXT_JAVA_INPUTSTREAM_H_INCLUDED_
#include <jni.h>
int nxt_java_initInputStream(JNIEnv *env, jobject cl);
#endif /* _NXT_JAVA_INPUTSTREAM_H_INCLUDED_ */

View File

@@ -0,0 +1,236 @@
/*
* Copyright (C) NGINX, Inc.
*/
#include <nxt_auto_config.h>
#include <jni.h>
#include <nxt_unit.h>
#include "nxt_jni.h"
#include "nxt_jni_OutputStream.h"
#include "nxt_jni_URLClassLoader.h"
static void JNICALL nxt_java_OutputStream_writeByte(JNIEnv *env, jclass cls,
jlong req_info_ptr, jint b);
static nxt_unit_buf_t *nxt_java_OutputStream_req_buf(JNIEnv *env,
nxt_unit_request_info_t *req);
static void JNICALL nxt_java_OutputStream_write(JNIEnv *env, jclass cls,
jlong req_info_ptr, jarray b, jint off, jint len);
static void JNICALL nxt_java_OutputStream_flush(JNIEnv *env, jclass cls,
jlong req_info_ptr);
static void JNICALL nxt_java_OutputStream_close(JNIEnv *env, jclass cls,
jlong req_info_ptr);
static jclass nxt_java_OutputStream_class;
int
nxt_java_initOutputStream(JNIEnv *env, jobject cl)
{
int res;
jclass cls;
cls = nxt_java_loadClass(env, cl, "nginx.unit.OutputStream");
if (cls == NULL) {
return NXT_UNIT_ERROR;
}
nxt_java_OutputStream_class = (*env)->NewGlobalRef(env, cls);
(*env)->DeleteLocalRef(env, cls);
cls = nxt_java_OutputStream_class;
JNINativeMethod os_methods[] = {
{ (char *) "write",
(char *) "(JI)V",
nxt_java_OutputStream_writeByte },
{ (char *) "write",
(char *) "(J[BII)V",
nxt_java_OutputStream_write },
{ (char *) "flush",
(char *) "(J)V",
nxt_java_OutputStream_flush },
{ (char *) "close",
(char *) "(J)V",
nxt_java_OutputStream_close },
};
res = (*env)->RegisterNatives(env, nxt_java_OutputStream_class,
os_methods,
sizeof(os_methods) / sizeof(os_methods[0]));
nxt_unit_debug(NULL, "registered OutputStream methods: %d", res);
if (res != 0) {
(*env)->DeleteGlobalRef(env, cls);
return NXT_UNIT_ERROR;
}
return NXT_UNIT_OK;
}
static void JNICALL
nxt_java_OutputStream_writeByte(JNIEnv *env, jclass cls, jlong req_info_ptr,
jint b)
{
nxt_unit_buf_t *buf;
nxt_unit_request_info_t *req;
nxt_java_request_data_t *data;
req = nxt_jlong2ptr(req_info_ptr);
data = req->data;
buf = nxt_java_OutputStream_req_buf(env, req);
if (buf == NULL) {
return;
}
*buf->free++ = b;
if ((uint32_t) (buf->free - buf->start) >= data->buf_size) {
nxt_java_OutputStream_flush_buf(env, req);
}
}
int
nxt_java_OutputStream_flush_buf(JNIEnv *env, nxt_unit_request_info_t *req)
{
int rc;
nxt_java_request_data_t *data;
data = req->data;
if (!nxt_unit_response_is_init(req)) {
rc = nxt_unit_response_init(req, 200, 0, 0);
if (rc != NXT_UNIT_OK) {
nxt_java_throw_IOException(env, "Failed to allocate response");
return rc;
}
}
if (!nxt_unit_response_is_sent(req)) {
rc = nxt_unit_response_send(req);
if (rc != NXT_UNIT_OK) {
nxt_java_throw_IOException(env, "Failed to send response headers");
return rc;
}
}
if (data->buf != NULL) {
rc = nxt_unit_buf_send(data->buf);
if (rc != NXT_UNIT_OK) {
nxt_java_throw_IOException(env, "Failed to send buffer");
} else {
data->buf = NULL;
}
} else {
rc = NXT_UNIT_OK;
}
return rc;
}
static nxt_unit_buf_t *
nxt_java_OutputStream_req_buf(JNIEnv *env, nxt_unit_request_info_t *req)
{
uint32_t size;
nxt_unit_buf_t *buf;
nxt_java_request_data_t *data;
data = req->data;
buf = data->buf;
if (buf == NULL || buf->free >= buf->end) {
size = data->buf_size == 0 ? nxt_unit_buf_min() : data->buf_size;
buf = nxt_unit_response_buf_alloc(req, size);
if (buf == NULL) {
nxt_java_throw_IOException(env, "Failed to allocate buffer");
return NULL;
}
data->buf = buf;
}
return buf;
}
static void JNICALL
nxt_java_OutputStream_write(JNIEnv *env, jclass cls, jlong req_info_ptr,
jarray b, jint off, jint len)
{
int rc;
jint copy;
uint8_t *ptr;
nxt_unit_buf_t *buf;
nxt_unit_request_info_t *req;
nxt_java_request_data_t *data;
req = nxt_jlong2ptr(req_info_ptr);
data = req->data;
ptr = (*env)->GetPrimitiveArrayCritical(env, b, NULL);
while (len > 0) {
buf = nxt_java_OutputStream_req_buf(env, req);
if (buf == NULL) {
return;
}
copy = buf->end - buf->free;
copy = copy < len ? copy : len;
memcpy(buf->free, ptr + off, copy);
buf->free += copy;
len -= copy;
off += copy;
if ((uint32_t) (buf->free - buf->start) >= data->buf_size) {
rc = nxt_java_OutputStream_flush_buf(env, req);
if (rc != NXT_UNIT_OK) {
break;
}
}
}
(*env)->ReleasePrimitiveArrayCritical(env, b, ptr, 0);
}
static void JNICALL
nxt_java_OutputStream_flush(JNIEnv *env, jclass cls, jlong req_info_ptr)
{
nxt_unit_request_info_t *req;
nxt_java_request_data_t *data;
req = nxt_jlong2ptr(req_info_ptr);
data = req->data;
if (data->buf != NULL && data->buf->free > data->buf->start) {
nxt_java_OutputStream_flush_buf(env, req);
}
}
static void JNICALL
nxt_java_OutputStream_close(JNIEnv *env, jclass cls, jlong req_info_ptr)
{
nxt_java_OutputStream_flush_buf(env, nxt_jlong2ptr(req_info_ptr));
}

View File

@@ -0,0 +1,17 @@
/*
* Copyright (C) NGINX, Inc.
*/
#ifndef _NXT_JAVA_OUTPUTSTREAM_H_INCLUDED_
#define _NXT_JAVA_OUTPUTSTREAM_H_INCLUDED_
#include <jni.h>
int nxt_java_initOutputStream(JNIEnv *env, jobject cl);
int nxt_java_OutputStream_flush_buf(JNIEnv *env, nxt_unit_request_info_t *req);
#endif /* _NXT_JAVA_OUTPUTSTREAM_H_INCLUDED_ */

658
src/java/nxt_jni_Request.c Normal file
View File

@@ -0,0 +1,658 @@
/*
* Copyright (C) NGINX, Inc.
*/
#include <nxt_auto_config.h>
#include <nxt_unit.h>
#include <nxt_unit_request.h>
#include <jni.h>
#include <stdio.h>
#include <stdlib.h>
#include "nxt_jni.h"
#include "nxt_jni_Request.h"
#include "nxt_jni_URLClassLoader.h"
#include "nxt_jni_HeadersEnumeration.h"
#include "nxt_jni_HeaderNamesEnumeration.h"
static jstring JNICALL nxt_java_Request_getHeader(JNIEnv *env, jclass cls,
jlong req_ptr, jstring name, jint name_len);
static jobject JNICALL nxt_java_Request_getHeaderNames(JNIEnv *env, jclass cls,
jlong req_ptr);
static jobject JNICALL nxt_java_Request_getHeaders(JNIEnv *env, jclass cls,
jlong req_ptr, jstring name, jint name_len);
static jint JNICALL nxt_java_Request_getIntHeader(JNIEnv *env, jclass cls,
jlong req_ptr, jstring name, jint name_len);
static jstring JNICALL nxt_java_Request_getMethod(JNIEnv *env, jclass cls,
jlong req_ptr);
static jstring JNICALL nxt_java_Request_getQueryString(JNIEnv *env, jclass cls,
jlong req_ptr);
static jstring JNICALL nxt_java_Request_getRequestURI(JNIEnv *env, jclass cls,
jlong req_ptr);
static jlong JNICALL nxt_java_Request_getContentLength(JNIEnv *env, jclass cls,
jlong req_ptr);
static jstring JNICALL nxt_java_Request_getContentType(JNIEnv *env, jclass cls,
jlong req_ptr);
static jstring JNICALL nxt_java_Request_getLocalAddr(JNIEnv *env, jclass cls,
jlong req_ptr);
static jstring JNICALL nxt_java_Request_getLocalName(JNIEnv *env, jclass cls,
jlong req_ptr);
static jint JNICALL nxt_java_Request_getLocalPort(JNIEnv *env, jclass cls,
jlong req_ptr);
static jstring JNICALL nxt_java_Request_getProtocol(JNIEnv *env, jclass cls,
jlong req_ptr);
static jstring JNICALL nxt_java_Request_getRemoteAddr(JNIEnv *env, jclass cls,
jlong req_ptr);
static jstring JNICALL nxt_java_Request_getRemoteHost(JNIEnv *env, jclass cls,
jlong req_ptr);
static jint JNICALL nxt_java_Request_getRemotePort(JNIEnv *env, jclass cls,
jlong req_ptr);
static jstring JNICALL nxt_java_Request_getScheme(JNIEnv *env, jclass cls,
jlong req_ptr);
static jstring JNICALL nxt_java_Request_getServerName(JNIEnv *env, jclass cls,
jlong req_ptr);
static jint JNICALL nxt_java_Request_getServerPort(JNIEnv *env, jclass cls,
jlong req_ptr);
static void JNICALL nxt_java_Request_log(JNIEnv *env, jclass cls,
jlong req_info_ptr, jstring msg, jint msg_len);
static void JNICALL nxt_java_Request_trace(JNIEnv *env, jclass cls,
jlong req_info_ptr, jstring msg, jint msg_len);
static jobject JNICALL nxt_java_Request_getResponse(JNIEnv *env, jclass cls,
jlong req_info_ptr);
static jclass nxt_java_Request_class;
static jmethodID nxt_java_Request_ctor;
int
nxt_java_initRequest(JNIEnv *env, jobject cl)
{
int res;
jclass cls;
cls = nxt_java_loadClass(env, cl, "nginx.unit.Request");
if (cls == NULL) {
return NXT_UNIT_ERROR;
}
nxt_java_Request_class = (*env)->NewGlobalRef(env, cls);
(*env)->DeleteLocalRef(env, cls);
cls = nxt_java_Request_class;
nxt_java_Request_ctor = (*env)->GetMethodID(env, cls, "<init>", "(Lnginx/unit/Context;JJ)V");
if (nxt_java_Request_ctor == NULL) {
(*env)->DeleteGlobalRef(env, cls);
return NXT_UNIT_ERROR;
}
JNINativeMethod request_methods[] = {
{ (char *) "getHeader",
(char *) "(JLjava/lang/String;I)Ljava/lang/String;",
nxt_java_Request_getHeader },
{ (char *) "getHeaderNames",
(char *) "(J)Ljava/util/Enumeration;",
nxt_java_Request_getHeaderNames },
{ (char *) "getHeaders",
(char *) "(JLjava/lang/String;I)Ljava/util/Enumeration;",
nxt_java_Request_getHeaders },
{ (char *) "getIntHeader",
(char *) "(JLjava/lang/String;I)I",
nxt_java_Request_getIntHeader },
{ (char *) "getMethod",
(char *) "(J)Ljava/lang/String;",
nxt_java_Request_getMethod },
{ (char *) "getQueryString",
(char *) "(J)Ljava/lang/String;",
nxt_java_Request_getQueryString },
{ (char *) "getRequestURI",
(char *) "(J)Ljava/lang/String;",
nxt_java_Request_getRequestURI },
{ (char *) "getContentLength",
(char *) "(J)J",
nxt_java_Request_getContentLength },
{ (char *) "getContentType",
(char *) "(J)Ljava/lang/String;",
nxt_java_Request_getContentType },
{ (char *) "getLocalAddr",
(char *) "(J)Ljava/lang/String;",
nxt_java_Request_getLocalAddr },
{ (char *) "getLocalName",
(char *) "(J)Ljava/lang/String;",
nxt_java_Request_getLocalName },
{ (char *) "getLocalPort",
(char *) "(J)I",
nxt_java_Request_getLocalPort },
{ (char *) "getProtocol",
(char *) "(J)Ljava/lang/String;",
nxt_java_Request_getProtocol },
{ (char *) "getRemoteAddr",
(char *) "(J)Ljava/lang/String;",
nxt_java_Request_getRemoteAddr },
{ (char *) "getRemoteHost",
(char *) "(J)Ljava/lang/String;",
nxt_java_Request_getRemoteHost },
{ (char *) "getRemotePort",
(char *) "(J)I",
nxt_java_Request_getRemotePort },
{ (char *) "getScheme",
(char *) "(J)Ljava/lang/String;",
nxt_java_Request_getScheme },
{ (char *) "getServerName",
(char *) "(J)Ljava/lang/String;",
nxt_java_Request_getServerName },
{ (char *) "getServerPort",
(char *) "(J)I",
nxt_java_Request_getServerPort },
{ (char *) "log",
(char *) "(JLjava/lang/String;I)V",
nxt_java_Request_log },
{ (char *) "trace",
(char *) "(JLjava/lang/String;I)V",
nxt_java_Request_trace },
{ (char *) "getResponse",
(char *) "(J)Lnginx/unit/Response;",
nxt_java_Request_getResponse },
};
res = (*env)->RegisterNatives(env, nxt_java_Request_class,
request_methods,
sizeof(request_methods) / sizeof(request_methods[0]));
nxt_unit_debug(NULL, "registered Request methods: %d", res);
if (res != 0) {
nxt_unit_warn(NULL, "registering natives for Request failed");
goto failed;
}
res = nxt_java_initHeadersEnumeration(env, cl);
if (res != NXT_UNIT_OK) {
goto failed;
}
res = nxt_java_initHeaderNamesEnumeration(env, cl);
if (res != NXT_UNIT_OK) {
goto failed;
}
return NXT_UNIT_OK;
failed:
(*env)->DeleteGlobalRef(env, cls);
return NXT_UNIT_ERROR;
}
jobject
nxt_java_newRequest(JNIEnv *env, jobject ctx, nxt_unit_request_info_t *req)
{
return (*env)->NewObject(env, nxt_java_Request_class,
nxt_java_Request_ctor, ctx, nxt_ptr2jlong(req),
nxt_ptr2jlong(req->request));
}
static jstring JNICALL
nxt_java_Request_getHeader(JNIEnv *env, jclass cls, jlong req_ptr,
jstring name, jint name_len)
{
const char *name_str;
nxt_unit_field_t *f;
nxt_unit_request_t *r;
name_str = (*env)->GetStringUTFChars(env, name, NULL);
if (name_str == NULL) {
return NULL;
}
r = nxt_jlong2ptr(req_ptr);
f = nxt_java_findHeader(r->fields, r->fields + r->fields_count,
name_str, name_len);
(*env)->ReleaseStringUTFChars(env, name, name_str);
if (f == NULL) {
return NULL;
}
return (*env)->NewStringUTF(env, nxt_unit_sptr_get(&f->value));
}
static jobject JNICALL
nxt_java_Request_getHeaderNames(JNIEnv *env, jclass cls, jlong req_ptr)
{
nxt_unit_request_t *r;
r = nxt_jlong2ptr(req_ptr);
return nxt_java_newHeaderNamesEnumeration(env, r->fields, r->fields_count);
}
static jobject JNICALL
nxt_java_Request_getHeaders(JNIEnv *env, jclass cls, jlong req_ptr,
jstring name, jint name_len)
{
const char *name_str;
nxt_unit_field_t *f;
nxt_unit_request_t *r;
name_str = (*env)->GetStringUTFChars(env, name, NULL);
if (name_str == NULL) {
return NULL;
}
r = nxt_jlong2ptr(req_ptr);
f = nxt_java_findHeader(r->fields, r->fields + r->fields_count,
name_str, name_len);
(*env)->ReleaseStringUTFChars(env, name, name_str);
if (f == NULL) {
f = r->fields + r->fields_count;
}
return nxt_java_newHeadersEnumeration(env, r->fields, r->fields_count,
f - r->fields);
}
static jint JNICALL
nxt_java_Request_getIntHeader(JNIEnv *env, jclass cls, jlong req_ptr,
jstring name, jint name_len)
{
jint res;
char *value, *end;
const char *name_str;
nxt_unit_field_t *f;
nxt_unit_request_t *r;
res = -1;
name_str = (*env)->GetStringUTFChars(env, name, NULL);
if (name_str == NULL) {
return res;
}
r = nxt_jlong2ptr(req_ptr);
f = nxt_java_findHeader(r->fields, r->fields + r->fields_count,
name_str, name_len);
(*env)->ReleaseStringUTFChars(env, name, name_str);
if (f == NULL) {
return res;
}
value = nxt_unit_sptr_get(&f->value);
end = value + f->value_length;
res = strtol(value, &end, 10);
if (end < value + f->value_length) {
// TODO throw NumberFormatException.forInputString(value)
}
return res;
}
static jstring JNICALL
nxt_java_Request_getMethod(JNIEnv *env, jclass cls, jlong req_ptr)
{
nxt_unit_request_t *r;
r = nxt_jlong2ptr(req_ptr);
return (*env)->NewStringUTF(env, nxt_unit_sptr_get(&r->method));
}
static jstring JNICALL
nxt_java_Request_getQueryString(JNIEnv *env, jclass cls, jlong req_ptr)
{
char *query;
nxt_unit_request_t *r;
r = nxt_jlong2ptr(req_ptr);
if (r->query.offset != 0) {
query = nxt_unit_sptr_get(&r->query);
return (*env)->NewStringUTF(env, query);
}
return NULL;
}
static jstring JNICALL
nxt_java_Request_getRequestURI(JNIEnv *env, jclass cls, jlong req_ptr)
{
char *target, *query;
nxt_unit_request_t *r;
r = nxt_jlong2ptr(req_ptr);
target = nxt_unit_sptr_get(&r->target);
if (r->query.offset != 0) {
query = nxt_unit_sptr_get(&r->query);
return nxt_java_newString(env, target, query - target - 1);
}
return (*env)->NewStringUTF(env, target);
}
static jlong JNICALL
nxt_java_Request_getContentLength(JNIEnv *env, jclass cls, jlong req_ptr)
{
nxt_unit_request_t *r;
r = nxt_jlong2ptr(req_ptr);
return r->content_length;
}
static jstring JNICALL
nxt_java_Request_getContentType(JNIEnv *env, jclass cls, jlong req_ptr)
{
nxt_unit_field_t *f;
nxt_unit_request_t *r;
r = nxt_jlong2ptr(req_ptr);
if (r->content_type_field != NXT_UNIT_NONE_FIELD) {
f = r->fields + r->content_type_field;
return (*env)->NewStringUTF(env, nxt_unit_sptr_get(&f->value));
}
return NULL;
}
static jstring JNICALL
nxt_java_Request_getLocalAddr(JNIEnv *env, jclass cls, jlong req_ptr)
{
nxt_unit_request_t *r;
r = nxt_jlong2ptr(req_ptr);
return nxt_java_newString(env, nxt_unit_sptr_get(&r->local),
r->local_length);
}
static jstring JNICALL
nxt_java_Request_getLocalName(JNIEnv *env, jclass cls, jlong req_ptr)
{
char *local, *colon;
nxt_unit_request_t *r;
r = nxt_jlong2ptr(req_ptr);
local = nxt_unit_sptr_get(&r->local);
colon = memchr(local, ':', r->local_length);
if (colon == NULL) {
colon = local + r->local_length;
}
return nxt_java_newString(env, local, colon - local);
}
static jint JNICALL
nxt_java_Request_getLocalPort(JNIEnv *env, jclass cls, jlong req_ptr)
{
jint res;
char *local, *colon, tmp;
nxt_unit_request_t *r;
r = nxt_jlong2ptr(req_ptr);
local = nxt_unit_sptr_get(&r->local);
colon = memchr(local, ':', r->local_length);
if (colon == NULL) {
return 80;
}
tmp = local[r->local_length];
local[r->local_length] = '\0';
res = strtol(colon + 1, NULL, 10);
local[r->local_length] = tmp;
return res;
}
static jstring JNICALL
nxt_java_Request_getProtocol(JNIEnv *env, jclass cls, jlong req_ptr)
{
nxt_unit_request_t *r;
r = nxt_jlong2ptr(req_ptr);
return (*env)->NewStringUTF(env, nxt_unit_sptr_get(&r->version));
}
static jstring JNICALL
nxt_java_Request_getRemoteAddr(JNIEnv *env, jclass cls, jlong req_ptr)
{
nxt_unit_request_t *r;
r = nxt_jlong2ptr(req_ptr);
return nxt_java_newString(env, nxt_unit_sptr_get(&r->remote),
r->remote_length);
}
static jstring JNICALL
nxt_java_Request_getRemoteHost(JNIEnv *env, jclass cls, jlong req_ptr)
{
char *remote, *colon;
nxt_unit_request_t *r;
r = nxt_jlong2ptr(req_ptr);
remote = nxt_unit_sptr_get(&r->remote);
colon = memchr(remote, ':', r->remote_length);
if (colon == NULL) {
colon = remote + r->remote_length;
}
return nxt_java_newString(env, remote, colon - remote);
}
static jint JNICALL
nxt_java_Request_getRemotePort(JNIEnv *env, jclass cls, jlong req_ptr)
{
jint res;
char *remote, *colon, tmp;
nxt_unit_request_t *r;
r = nxt_jlong2ptr(req_ptr);
remote = nxt_unit_sptr_get(&r->remote);
colon = memchr(remote, ':', r->remote_length);
if (colon == NULL) {
return 80;
}
tmp = remote[r->remote_length];
remote[r->remote_length] = '\0';
res = strtol(colon + 1, NULL, 10);
remote[r->remote_length] = tmp;
return res;
}
static jstring JNICALL
nxt_java_Request_getScheme(JNIEnv *env, jclass cls, jlong req_ptr)
{
return (*env)->NewStringUTF(env, "http");
}
static jstring JNICALL
nxt_java_Request_getServerName(JNIEnv *env, jclass cls, jlong req_ptr)
{
char *host, *colon;
nxt_unit_field_t *f;
nxt_unit_request_t *r;
r = nxt_jlong2ptr(req_ptr);
f = nxt_java_findHeader(r->fields, r->fields + r->fields_count,
"Host", 4);
if (f != NULL) {
host = nxt_unit_sptr_get(&f->value);
colon = memchr(host, ':', f->value_length);
if (colon == NULL) {
colon = host + f->value_length;
}
return nxt_java_newString(env, host, colon - host);
}
return nxt_java_Request_getLocalName(env, cls, req_ptr);
}
static jint JNICALL
nxt_java_Request_getServerPort(JNIEnv *env, jclass cls, jlong req_ptr)
{
jint res;
char *host, *colon, tmp;
nxt_unit_field_t *f;
nxt_unit_request_t *r;
r = nxt_jlong2ptr(req_ptr);
f = nxt_java_findHeader(r->fields, r->fields + r->fields_count,
"Host", 4);
if (f != NULL) {
host = nxt_unit_sptr_get(&f->value);
colon = memchr(host, ':', f->value_length);
if (colon == NULL) {
return 80;
}
tmp = host[f->value_length];
host[f->value_length] = '\0';
res = strtol(colon + 1, NULL, 10);
host[f->value_length] = tmp;
return res;
}
return nxt_java_Request_getLocalPort(env, cls, req_ptr);
}
static void JNICALL
nxt_java_Request_log(JNIEnv *env, jclass cls, jlong req_info_ptr, jstring msg,
jint msg_len)
{
const char *msg_str;
nxt_unit_request_info_t *req;
req = nxt_jlong2ptr(req_info_ptr);
msg_str = (*env)->GetStringUTFChars(env, msg, NULL);
if (msg_str == NULL) {
return;
}
nxt_unit_req_log(req, NXT_UNIT_LOG_INFO, "%.*s", msg_len, msg_str);
(*env)->ReleaseStringUTFChars(env, msg, msg_str);
}
static void JNICALL
nxt_java_Request_trace(JNIEnv *env, jclass cls, jlong req_info_ptr, jstring msg,
jint msg_len)
{
#if (NXT_DEBUG)
const char *msg_str;
nxt_unit_request_info_t *req;
req = nxt_jlong2ptr(req_info_ptr);
msg_str = (*env)->GetStringUTFChars(env, msg, NULL);
if (msg_str == NULL) {
return;
}
nxt_unit_req_debug(req, "%.*s", msg_len, msg_str);
(*env)->ReleaseStringUTFChars(env, msg, msg_str);
#endif
}
static jobject JNICALL
nxt_java_Request_getResponse(JNIEnv *env, jclass cls, jlong req_info_ptr)
{
nxt_unit_request_info_t *req;
nxt_java_request_data_t *data;
req = nxt_jlong2ptr(req_info_ptr);
data = req->data;
return data->jresp;
}

View File

@@ -0,0 +1,18 @@
/*
* Copyright (C) NGINX, Inc.
*/
#ifndef _NXT_JAVA_REQUEST_H_INCLUDED_
#define _NXT_JAVA_REQUEST_H_INCLUDED_
#include <jni.h>
#include <nxt_unit_typedefs.h>
int nxt_java_initRequest(JNIEnv *env, jobject cl);
jobject nxt_java_newRequest(JNIEnv *env, jobject ctx, nxt_unit_request_info_t *req);
#endif /* _NXT_JAVA_REQUEST_H_INCLUDED_ */

1105
src/java/nxt_jni_Response.c Normal file

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,18 @@
/*
* Copyright (C) NGINX, Inc.
*/
#ifndef _NXT_JAVA_RESPONSE_H_INCLUDED_
#define _NXT_JAVA_RESPONSE_H_INCLUDED_
#include <jni.h>
#include <nxt_unit_typedefs.h>
int nxt_java_initResponse(JNIEnv *env, jobject cl);
jobject nxt_java_newResponse(JNIEnv *env, nxt_unit_request_info_t *req);
#endif /* _NXT_JAVA_RESPONSE_H_INCLUDED_ */

94
src/java/nxt_jni_Thread.c Normal file
View File

@@ -0,0 +1,94 @@
/*
* Copyright (C) NGINX, Inc.
*/
#include <nxt_unit.h>
#include <jni.h>
#include "nxt_jni_Thread.h"
static jclass nxt_java_Thread_class;
static jmethodID nxt_java_Thread_currentThread;
static jmethodID nxt_java_Thread_getContextClassLoader;
static jmethodID nxt_java_Thread_setContextClassLoader;
int
nxt_java_initThread(JNIEnv *env)
{
jclass cls;
cls = (*env)->FindClass(env, "java/lang/Thread");
if (cls == NULL) {
nxt_unit_warn(NULL, "java.lang.Thread not found");
return NXT_UNIT_ERROR;
}
nxt_java_Thread_class = (*env)->NewGlobalRef(env, cls);
(*env)->DeleteLocalRef(env, cls);
cls = nxt_java_Thread_class;
nxt_java_Thread_currentThread = (*env)->GetStaticMethodID(env, cls,
"currentThread", "()Ljava/lang/Thread;");
if (nxt_java_Thread_currentThread == NULL) {
nxt_unit_warn(NULL, "java.lang.Thread.currentThread() not found");
goto failed;
}
nxt_java_Thread_getContextClassLoader = (*env)->GetMethodID(env, cls,
"getContextClassLoader", "()Ljava/lang/ClassLoader;");
if (nxt_java_Thread_getContextClassLoader == NULL) {
nxt_unit_warn(NULL, "java.lang.Thread.getContextClassLoader() "
"not found");
goto failed;
}
nxt_java_Thread_setContextClassLoader = (*env)->GetMethodID(env, cls,
"setContextClassLoader", "(Ljava/lang/ClassLoader;)V");
if (nxt_java_Thread_setContextClassLoader == NULL) {
nxt_unit_warn(NULL, "java.lang.Thread.setContextClassLoader() "
"not found");
goto failed;
}
return NXT_UNIT_OK;
failed:
(*env)->DeleteGlobalRef(env, cls);
return NXT_UNIT_ERROR;
}
void
nxt_java_setContextClassLoader(JNIEnv *env, jobject cl)
{
jobject thread;
thread = (*env)->CallStaticObjectMethod(env, nxt_java_Thread_class,
nxt_java_Thread_currentThread);
if (thread == NULL) {
return;
}
(*env)->CallVoidMethod(env, thread, nxt_java_Thread_setContextClassLoader,
cl);
}
jobject
nxt_java_getContextClassLoader(JNIEnv *env)
{
jobject thread;
thread = (*env)->CallStaticObjectMethod(env, nxt_java_Thread_class,
nxt_java_Thread_currentThread);
if (thread == NULL) {
return NULL;
}
return (*env)->CallObjectMethod(env, thread,
nxt_java_Thread_getContextClassLoader);
}

20
src/java/nxt_jni_Thread.h Normal file
View File

@@ -0,0 +1,20 @@
/*
* Copyright (C) NGINX, Inc.
*/
#ifndef _NXT_JAVA_THREAD_H_INCLUDED_
#define _NXT_JAVA_THREAD_H_INCLUDED_
#include <jni.h>
int nxt_java_initThread(JNIEnv *env);
void nxt_java_setContextClassLoader(JNIEnv *env, jobject cl);
jobject nxt_java_getContextClassLoader(JNIEnv *env);
#endif /* _NXT_JAVA_THREAD_H_INCLUDED_ */

View File

@@ -0,0 +1,187 @@
/*
* Copyright (C) NGINX, Inc.
*/
#include <nxt_unit.h>
#include <jni.h>
#include "nxt_jni_URLClassLoader.h"
static jclass nxt_java_URLClassLoader_class;
static jmethodID nxt_java_URLClassLoader_ctor;
static jmethodID nxt_java_URLClassLoader_parent_ctor;
static jmethodID nxt_java_URLClassLoader_loadClass;
static jmethodID nxt_java_URLClassLoader_addURL;
static jclass nxt_java_URL_class;
static jmethodID nxt_java_URL_ctor;
int
nxt_java_initURLClassLoader(JNIEnv *env)
{
jclass cls;
cls = (*env)->FindClass(env, "java/net/URLClassLoader");
if (cls == NULL) {
nxt_unit_warn(NULL, "java.net.URLClassLoader not found");
return NXT_UNIT_ERROR;
}
nxt_java_URLClassLoader_class = (*env)->NewGlobalRef(env, cls);
(*env)->DeleteLocalRef(env, cls);
cls = nxt_java_URLClassLoader_class;
nxt_java_URLClassLoader_ctor = (*env)->GetMethodID(env, cls,
"<init>", "([Ljava/net/URL;)V");
if (nxt_java_URLClassLoader_ctor == NULL) {
nxt_unit_warn(NULL, "java.net.URLClassLoader constructor not found");
goto failed;
}
nxt_java_URLClassLoader_parent_ctor = (*env)->GetMethodID(env, cls,
"<init>", "([Ljava/net/URL;Ljava/lang/ClassLoader;)V");
if (nxt_java_URLClassLoader_ctor == NULL) {
nxt_unit_warn(NULL, "java.net.URLClassLoader constructor not found");
goto failed;
}
nxt_java_URLClassLoader_loadClass = (*env)->GetMethodID(env, cls,
"loadClass", "(Ljava/lang/String;)Ljava/lang/Class;");
if (nxt_java_URLClassLoader_loadClass == NULL) {
nxt_unit_warn(NULL, "java.net.URLClassLoader.loadClass not found");
goto failed;
}
nxt_java_URLClassLoader_addURL = (*env)->GetMethodID(env, cls,
"addURL", "(Ljava/net/URL;)V");
if (nxt_java_URLClassLoader_addURL == NULL) {
nxt_unit_warn(NULL, "java.net.URLClassLoader.addURL not found");
goto failed;
}
cls = (*env)->FindClass(env, "java/net/URL");
if (cls == NULL) {
nxt_unit_warn(NULL, "java.net.URL not found");
return NXT_UNIT_ERROR;
}
nxt_java_URL_class = (*env)->NewGlobalRef(env, cls);
(*env)->DeleteLocalRef(env, cls);
cls = nxt_java_URL_class;
nxt_java_URL_ctor = (*env)->GetMethodID(env, cls,
"<init>", "(Ljava/lang/String;)V");
if (nxt_java_URL_ctor == NULL) {
nxt_unit_warn(NULL, "java.net.URL constructor not found");
goto failed;
}
return NXT_UNIT_OK;
failed:
(*env)->DeleteGlobalRef(env, cls);
return NXT_UNIT_ERROR;
}
jobject
nxt_java_newURLClassLoader(JNIEnv *env, int url_count, char **urls)
{
jobjectArray jurls;
jurls = nxt_java_newURLs(env, url_count, urls);
if (jurls == NULL) {
return NULL;
}
return (*env)->NewObject(env, nxt_java_URLClassLoader_class,
nxt_java_URLClassLoader_ctor, jurls);
}
jobject
nxt_java_newURLClassLoader_parent(JNIEnv *env, int url_count, char **urls,
jobject parent)
{
jobjectArray jurls;
jurls = nxt_java_newURLs(env, url_count, urls);
if (jurls == NULL) {
return NULL;
}
return (*env)->NewObject(env, nxt_java_URLClassLoader_class,
nxt_java_URLClassLoader_parent_ctor, jurls,
parent);
}
jobjectArray
nxt_java_newURLs(JNIEnv *env, int url_count, char **urls)
{
int i;
jstring surl;
jobject jurl;
jobjectArray jurls;
jurls = (*env)->NewObjectArray(env, url_count, nxt_java_URL_class, NULL);
if (jurls == NULL) {
return NULL;
}
for (i = 0; i < url_count; i++) {
surl = (*env)->NewStringUTF(env, urls[i]);
if (surl == NULL) {
return NULL;
}
jurl = (*env)->NewObject(env, nxt_java_URL_class, nxt_java_URL_ctor,
surl);
if (jurl == NULL) {
return NULL;
}
(*env)->SetObjectArrayElement(env, jurls, i, jurl);
}
return jurls;
}
jclass
nxt_java_loadClass(JNIEnv *env, jobject cl, const char *name)
{
jstring jname;
jname = (*env)->NewStringUTF(env, name);
if (jname == NULL) {
return NULL;
}
return (*env)->CallObjectMethod(env, cl, nxt_java_URLClassLoader_loadClass,
jname);
}
void
nxt_java_addURL(JNIEnv *env, jobject cl, const char *url)
{
jstring surl;
jobject jurl;
surl = (*env)->NewStringUTF(env, url);
if (surl == NULL) {
return;
}
jurl = (*env)->NewObject(env, nxt_java_URL_class, nxt_java_URL_ctor, surl);
if (jurl == NULL) {
return;
}
(*env)->CallVoidMethod(env, cl, nxt_java_URLClassLoader_addURL, jurl);
}

View File

@@ -0,0 +1,27 @@
/*
* Copyright (C) NGINX, Inc.
*/
#ifndef _NXT_JAVA_URLCLASSLOADER_H_INCLUDED_
#define _NXT_JAVA_URLCLASSLOADER_H_INCLUDED_
#include <jni.h>
int nxt_java_initURLClassLoader(JNIEnv *env);
jobject nxt_java_newURLClassLoader(JNIEnv *env, int url_count, char **urls);
jobject nxt_java_newURLClassLoader_parent(JNIEnv *env, int url_count,
char **urls, jobject parent);
jobjectArray nxt_java_newURLs(JNIEnv *env, int url_count, char **urls);
jclass nxt_java_loadClass(JNIEnv *env, jobject cl, const char *name);
void nxt_java_addURL(JNIEnv *env, jobject cl, const char *url);
#endif /* _NXT_JAVA_URLCLASSLOADER_H_INCLUDED_ */

View File

@@ -331,6 +331,17 @@ nxt_app_start(nxt_task_t *task, void *data)
nxt_app = nxt_app_module_load(task, lang->file);
}
if (nxt_app->pre_init != NULL) {
ret = nxt_app->pre_init(task, data);
if (nxt_slow_path(ret != NXT_OK)) {
nxt_debug(task, "application pre_init failed");
} else {
nxt_debug(task, "application pre_init done");
}
}
if (app_conf->working_directory != NULL
&& app_conf->working_directory[0] != 0)
{
@@ -521,6 +532,9 @@ nxt_app_parse_type(u_char *p, size_t length)
} else if (nxt_str_eq(&str, "ruby", 4)) {
return NXT_APP_RUBY;
} else if (nxt_str_eq(&str, "java", 4)) {
return NXT_APP_JAVA;
}
return NXT_APP_UNKNOWN;

View File

@@ -20,6 +20,7 @@ typedef enum {
NXT_APP_PHP,
NXT_APP_PERL,
NXT_APP_RUBY,
NXT_APP_JAVA,
NXT_APP_UNKNOWN,
} nxt_app_type_t;
@@ -70,6 +71,14 @@ typedef struct {
} nxt_ruby_app_conf_t;
typedef struct {
nxt_conf_value_t *classpath;
char *webapp;
nxt_conf_value_t *options;
char *unit_jars;
} nxt_java_app_conf_t;
struct nxt_common_app_conf_s {
nxt_str_t name;
nxt_str_t type;
@@ -85,6 +94,7 @@ struct nxt_common_app_conf_s {
nxt_php_app_conf_t php;
nxt_perl_app_conf_t perl;
nxt_ruby_app_conf_t ruby;
nxt_java_app_conf_t java;
} u;
};
@@ -152,6 +162,8 @@ struct nxt_app_module_s {
nxt_str_t type;
const char *version;
nxt_int_t (*pre_init)(nxt_task_t *task,
nxt_common_app_conf_t *conf);
nxt_int_t (*init)(nxt_task_t *task,
nxt_common_app_conf_t *conf);
};

View File

@@ -125,7 +125,7 @@ void nxt_conf_set_element(nxt_conf_value_t *array, nxt_uint_t index,
nxt_conf_value_t *value);
nxt_int_t nxt_conf_set_element_string_dup(nxt_conf_value_t *array, nxt_mp_t *mp,
nxt_uint_t index, nxt_str_t *value);
nxt_uint_t nxt_conf_array_elements_count(nxt_conf_value_t *value);
NXT_EXPORT nxt_uint_t nxt_conf_array_elements_count(nxt_conf_value_t *value);
void nxt_conf_array_qsort(nxt_conf_value_t *value,
int (*compare)(const void *, const void *));

View File

@@ -88,6 +88,10 @@ static nxt_int_t nxt_conf_vldt_argument(nxt_conf_validation_t *vldt,
nxt_conf_value_t *value);
static nxt_int_t nxt_conf_vldt_php_option(nxt_conf_validation_t *vldt,
nxt_str_t *name, nxt_conf_value_t *value);
static nxt_int_t nxt_conf_vldt_java_classpath(nxt_conf_validation_t *vldt,
nxt_conf_value_t *value);
static nxt_int_t nxt_conf_vldt_java_option(nxt_conf_validation_t *vldt,
nxt_conf_value_t *value);
static nxt_conf_vldt_object_t nxt_conf_vldt_http_members[] = {
@@ -423,6 +427,31 @@ static nxt_conf_vldt_object_t nxt_conf_vldt_ruby_members[] = {
};
static nxt_conf_vldt_object_t nxt_conf_vldt_java_members[] = {
{ nxt_string("classpath"),
NXT_CONF_VLDT_ARRAY,
&nxt_conf_vldt_array_iterator,
(void *) &nxt_conf_vldt_java_classpath},
{ nxt_string("webapp"),
NXT_CONF_VLDT_STRING,
NULL,
NULL },
{ nxt_string("options"),
NXT_CONF_VLDT_ARRAY,
&nxt_conf_vldt_array_iterator,
(void *) &nxt_conf_vldt_java_option},
{ nxt_string("unit_jars"),
NXT_CONF_VLDT_STRING,
NULL,
NULL },
NXT_CONF_VLDT_NEXT(&nxt_conf_vldt_common_members)
};
nxt_int_t
nxt_conf_validate(nxt_conf_validation_t *vldt)
{
@@ -818,6 +847,7 @@ nxt_conf_vldt_app(nxt_conf_validation_t *vldt, nxt_str_t *name,
nxt_conf_vldt_php_members,
nxt_conf_vldt_perl_members,
nxt_conf_vldt_ruby_members,
nxt_conf_vldt_java_members,
};
ret = nxt_conf_vldt_type(vldt, name, value, NXT_CONF_VLDT_OBJECT);
@@ -1216,3 +1246,44 @@ nxt_conf_vldt_php_option(nxt_conf_validation_t *vldt, nxt_str_t *name,
return NXT_OK;
}
static nxt_int_t
nxt_conf_vldt_java_classpath(nxt_conf_validation_t *vldt, nxt_conf_value_t *value)
{
nxt_str_t str;
if (nxt_conf_type(value) != NXT_CONF_STRING) {
return nxt_conf_vldt_error(vldt, "The \"classpath\" array "
"must contain only string values.");
}
nxt_conf_get_string(value, &str);
if (nxt_memchr(str.start, '\0', str.length) != NULL) {
return nxt_conf_vldt_error(vldt, "The \"classpath\" array must not "
"contain strings with null character.");
}
return NXT_OK;
}
static nxt_int_t
nxt_conf_vldt_java_option(nxt_conf_validation_t *vldt, nxt_conf_value_t *value)
{
nxt_str_t str;
if (nxt_conf_type(value) != NXT_CONF_STRING) {
return nxt_conf_vldt_error(vldt, "The \"options\" array "
"must contain only string values.");
}
nxt_conf_get_string(value, &str);
if (nxt_memchr(str.start, '\0', str.length) != NULL) {
return nxt_conf_vldt_error(vldt, "The \"options\" array must not "
"contain strings with null character.");
}
return NXT_OK;
}

View File

@@ -18,6 +18,7 @@ nxt_app_module_t nxt_external_module = {
NULL,
nxt_string("external"),
"*",
NULL,
nxt_external_init,
};

462
src/nxt_java.c Normal file
View File

@@ -0,0 +1,462 @@
/*
* Copyright (C) NGINX, Inc.
*/
#include <jni.h>
#include <nxt_main.h>
#include <nxt_runtime.h>
#include <nxt_router.h>
#include <nxt_unit.h>
#include <nxt_unit_field.h>
#include <nxt_unit_request.h>
#include <nxt_unit_response.h>
#include <java/nxt_jni.h>
#include "java/nxt_jni_Thread.h"
#include "java/nxt_jni_Context.h"
#include "java/nxt_jni_Request.h"
#include "java/nxt_jni_Response.h"
#include "java/nxt_jni_InputStream.h"
#include "java/nxt_jni_OutputStream.h"
#include "java/nxt_jni_URLClassLoader.h"
#include "nxt_jars.h"
static nxt_int_t nxt_java_pre_init(nxt_task_t *task,
nxt_common_app_conf_t *conf);
static nxt_int_t nxt_java_init(nxt_task_t *task, nxt_common_app_conf_t *conf);
static void nxt_java_request_handler(nxt_unit_request_info_t *req);
static uint32_t compat[] = {
NXT_VERNUM, NXT_DEBUG,
};
char *nxt_java_modules;
#define NXT_STRING(x) _NXT_STRING(x)
#define _NXT_STRING(x) #x
NXT_EXPORT nxt_app_module_t nxt_app_module = {
sizeof(compat),
compat,
nxt_string("java"),
NXT_STRING(NXT_JAVA_VERSION),
nxt_java_pre_init,
nxt_java_init,
};
typedef struct {
JNIEnv *env;
jobject ctx;
} nxt_java_data_t;
static nxt_int_t
nxt_java_pre_init(nxt_task_t *task, nxt_common_app_conf_t *conf)
{
const char *unit_jars;
unit_jars = conf->u.java.unit_jars;
if (unit_jars == NULL) {
unit_jars = NXT_JARS;
}
nxt_java_modules = realpath(unit_jars, NULL);
if (nxt_java_modules == NULL) {
nxt_alert(task, "realpath(%s) failed: %E", NXT_JARS, nxt_errno);
return NXT_ERROR;
}
return NXT_OK;
}
static char **
nxt_java_module_jars(const char *jars[], int jar_count)
{
char **res, *jurl;
nxt_int_t modules_len, jlen, i;
const char **jar;
res = nxt_malloc(jar_count * sizeof(char*));
if (res == NULL) {
return NULL;
}
modules_len = nxt_strlen(nxt_java_modules);
for (i = 0, jar = jars; *jar != NULL; jar++) {
jlen = nxt_length("file:") + modules_len + nxt_length("/")
+ nxt_strlen(*jar) + 1;
jurl = nxt_malloc(jlen);
if (jurl == NULL) {
return NULL;
}
res[i++] = jurl;
jurl = nxt_cpymem(jurl, "file:", nxt_length("file:"));
jurl = nxt_cpymem(jurl, nxt_java_modules, modules_len);
*jurl++ = '/';
jurl = nxt_cpymem(jurl, *jar, nxt_strlen(*jar));
*jurl++ = '\0';
}
return res;
}
static nxt_int_t
nxt_java_init(nxt_task_t *task, nxt_common_app_conf_t *conf)
{
jint rc;
char *opt, *real_path;
char **classpath_arr, **unit_jars, **system_jars;
JavaVM *jvm;
JNIEnv *env;
jobject cl, classpath;
nxt_str_t str;
nxt_int_t opt_len, real_path_len;
nxt_uint_t i, unit_jars_count, classpath_count, system_jars_count;
JavaVMOption *jvm_opt;
JavaVMInitArgs jvm_args;
nxt_unit_ctx_t *ctx;
nxt_unit_init_t java_init;
nxt_java_data_t data;
nxt_conf_value_t *value;
nxt_java_app_conf_t *c;
//setenv("ASAN_OPTIONS", "handle_segv=0", 1);
jvm_args.version = JNI_VERSION_1_6;
jvm_args.nOptions = 0;
jvm_args.ignoreUnrecognized = 0;
c = &conf->u.java;
if (c->options != NULL) {
jvm_args.nOptions += nxt_conf_array_elements_count(c->options);
}
jvm_opt = nxt_malloc(jvm_args.nOptions * sizeof(JavaVMOption));
if (jvm_opt == NULL) {
nxt_alert(task, "failed to allocate jvm_opt");
return NXT_ERROR;
}
jvm_args.options = jvm_opt;
unit_jars_count = nxt_nitems(nxt_java_unit_jars) - 1;
unit_jars = nxt_java_module_jars(nxt_java_unit_jars, unit_jars_count);
if (unit_jars == NULL) {
nxt_alert(task, "failed to allocate buffer for unit_jars array");
return NXT_ERROR;
}
system_jars_count = nxt_nitems(nxt_java_system_jars) - 1;
system_jars = nxt_java_module_jars(nxt_java_system_jars, system_jars_count);
if (system_jars == NULL) {
nxt_alert(task, "failed to allocate buffer for system_jars array");
return NXT_ERROR;
}
if (c->options != NULL) {
for (i = 0; /* void */ ; i++) {
value = nxt_conf_get_array_element(c->options, i);
if (value == NULL) {
break;
}
nxt_conf_get_string(value, &str);
opt = nxt_malloc(str.length + 1);
if (opt == NULL) {
nxt_alert(task, "failed to allocate jvm_opt");
return NXT_ERROR;
}
memcpy(opt, str.start, str.length);
opt[str.length] = '\0';
jvm_opt[i].optionString = opt;
}
}
if (c->classpath != NULL) {
classpath_count = nxt_conf_array_elements_count(c->classpath);
classpath_arr = nxt_malloc(classpath_count * sizeof(char *));
for (i = 0; /* void */ ; i++) {
value = nxt_conf_get_array_element(c->classpath, i);
if (value == NULL) {
break;
}
nxt_conf_get_string(value, &str);
opt_len = str.length + 1;
char *sc = memchr(str.start, ':', str.length);
if (sc == NULL && str.start[0] == '/') {
opt_len += nxt_length("file:");
}
opt = nxt_malloc(opt_len);
if (opt == NULL) {
nxt_alert(task, "failed to allocate classpath");
return NXT_ERROR;
}
if (sc == NULL && str.start[0] != '/') {
nxt_memcpy(opt, str.start, str.length);
opt[str.length] = '\0';
real_path = realpath(opt, NULL);
if (real_path == NULL) {
nxt_alert(task, "realpath(%s) failed: %E", opt, nxt_errno);
return NXT_ERROR;
}
real_path_len = nxt_strlen(real_path);
free(opt);
opt_len = nxt_length("file:") + real_path_len + 1;
opt = nxt_malloc(opt_len);
if (opt == NULL) {
nxt_alert(task, "failed to allocate classpath");
return NXT_ERROR;
}
} else {
real_path = (char *) str.start; /* I love this cast! */
real_path_len = str.length;
}
classpath_arr[i] = opt;
if (sc == NULL) {
opt = nxt_cpymem(opt, "file:", nxt_length("file:"));
}
opt = nxt_cpymem(opt, real_path, real_path_len);
*opt = '\0';
}
} else {
classpath_count = 0;
classpath_arr = NULL;
}
rc = JNI_CreateJavaVM(&jvm, (void **) &env, &jvm_args);
if (rc != JNI_OK) {
nxt_alert(task, "failed to create Java VM: %d", (int) rc);
return NXT_ERROR;
}
rc = nxt_java_initThread(env);
if (rc != NXT_UNIT_OK) {
nxt_alert(task, "nxt_java_initThread() failed");
goto env_failed;
}
rc = nxt_java_initURLClassLoader(env);
if (rc != NXT_UNIT_OK) {
nxt_alert(task, "nxt_java_initURLClassLoader() failed");
goto env_failed;
}
cl = nxt_java_newURLClassLoader(env, system_jars_count, system_jars);
if (cl == NULL) {
nxt_alert(task, "nxt_java_newURLClassLoader failed");
goto env_failed;
}
nxt_java_setContextClassLoader(env, cl);
cl = nxt_java_newURLClassLoader_parent(env, unit_jars_count, unit_jars, cl);
if (cl == NULL) {
nxt_alert(task, "nxt_java_newURLClassLoader_parent failed");
goto env_failed;
}
nxt_java_setContextClassLoader(env, cl);
rc = nxt_java_initContext(env, cl);
if (rc != NXT_UNIT_OK) {
nxt_alert(task, "nxt_java_initContext() failed");
goto env_failed;
}
rc = nxt_java_initRequest(env, cl);
if (rc != NXT_UNIT_OK) {
nxt_alert(task, "nxt_java_initRequest() failed");
goto env_failed;
}
rc = nxt_java_initResponse(env, cl);
if (rc != NXT_UNIT_OK) {
nxt_alert(task, "nxt_java_initResponse() failed");
goto env_failed;
}
rc = nxt_java_initInputStream(env, cl);
if (rc != NXT_UNIT_OK) {
nxt_alert(task, "nxt_java_initInputStream() failed");
goto env_failed;
}
rc = nxt_java_initOutputStream(env, cl);
if (rc != NXT_UNIT_OK) {
nxt_alert(task, "nxt_java_initOutputStream() failed");
goto env_failed;
}
nxt_java_jni_init(env);
if (rc != NXT_UNIT_OK) {
nxt_alert(task, "nxt_java_jni_init() failed");
goto env_failed;
}
classpath = nxt_java_newURLs(env, classpath_count, classpath_arr);
if (classpath == NULL) {
nxt_alert(task, "nxt_java_newURLs failed");
goto env_failed;
}
data.env = env;
data.ctx = nxt_java_startContext(env, c->webapp, classpath);
if ((*env)->ExceptionCheck(env)) {
nxt_alert(task, "Unhandled exception in application start");
(*env)->ExceptionDescribe(env);
return NXT_ERROR;
}
nxt_unit_default_init(task, &java_init);
java_init.callbacks.request_handler = nxt_java_request_handler;
java_init.request_data_size = sizeof(nxt_java_request_data_t);
java_init.data = &data;
ctx = nxt_unit_init(&java_init);
if (nxt_slow_path(ctx == NULL)) {
nxt_alert(task, "nxt_unit_init() failed");
return NXT_ERROR;
}
rc = nxt_unit_run(ctx);
if (nxt_slow_path(rc != NXT_UNIT_OK)) {
/* TODO report error */
}
nxt_unit_done(ctx);
nxt_java_stopContext(env, data.ctx);
if ((*env)->ExceptionCheck(env)) {
(*env)->ExceptionDescribe(env);
}
(*jvm)->DestroyJavaVM(jvm);
exit(0);
return NXT_OK;
env_failed:
if ((*env)->ExceptionCheck(env)) {
(*env)->ExceptionDescribe(env);
}
return NXT_ERROR;
}
static void
nxt_java_request_handler(nxt_unit_request_info_t *req)
{
JNIEnv *env;
jobject jreq, jresp;
nxt_java_data_t *java_data;
nxt_java_request_data_t *data;
java_data = req->unit->data;
env = java_data->env;
data = req->data;
jreq = nxt_java_newRequest(env, java_data->ctx, req);
if (jreq == NULL) {
nxt_unit_req_alert(req, "failed to create Request instance");
if ((*env)->ExceptionCheck(env)) {
(*env)->ExceptionDescribe(env);
(*env)->ExceptionClear(env);
}
nxt_unit_request_done(req, NXT_UNIT_ERROR);
return;
}
jresp = nxt_java_newResponse(env, req);
if (jresp == NULL) {
nxt_unit_req_alert(req, "failed to create Response instance");
if ((*env)->ExceptionCheck(env)) {
(*env)->ExceptionDescribe(env);
(*env)->ExceptionClear(env);
}
(*env)->DeleteLocalRef(env, jreq);
nxt_unit_request_done(req, NXT_UNIT_ERROR);
return;
}
data->header_size = 10 * 1024;
data->buf_size = 32 * 1024; /* from Jetty */
data->jreq = jreq;
data->jresp = jresp;
data->buf = NULL;
nxt_unit_request_group_dup_fields(req);
nxt_java_service(env, java_data->ctx, jreq, jresp);
if ((*env)->ExceptionCheck(env)) {
(*env)->ExceptionDescribe(env);
(*env)->ExceptionClear(env);
}
if (!nxt_unit_response_is_init(req)) {
nxt_unit_response_init(req, 200, 0, 0);
}
if (!nxt_unit_response_is_sent(req)) {
nxt_unit_response_send(req);
}
if (data->buf != NULL) {
nxt_unit_buf_send(data->buf);
data->buf = NULL;
}
(*env)->DeleteLocalRef(env, jresp);
(*env)->DeleteLocalRef(env, jreq);
nxt_unit_request_done(req, NXT_UNIT_OK);
}

View File

@@ -219,12 +219,38 @@ static nxt_conf_map_t nxt_ruby_app_conf[] = {
};
static nxt_conf_map_t nxt_java_app_conf[] = {
{
nxt_string("classpath"),
NXT_CONF_MAP_PTR,
offsetof(nxt_common_app_conf_t, u.java.classpath),
},
{
nxt_string("webapp"),
NXT_CONF_MAP_CSTRZ,
offsetof(nxt_common_app_conf_t, u.java.webapp),
},
{
nxt_string("options"),
NXT_CONF_MAP_PTR,
offsetof(nxt_common_app_conf_t, u.java.options),
},
{
nxt_string("unit_jars"),
NXT_CONF_MAP_CSTRZ,
offsetof(nxt_common_app_conf_t, u.java.unit_jars),
},
};
static nxt_conf_app_map_t nxt_app_maps[] = {
{ nxt_nitems(nxt_external_app_conf), nxt_external_app_conf },
{ nxt_nitems(nxt_python_app_conf), nxt_python_app_conf },
{ nxt_nitems(nxt_php_app_conf), nxt_php_app_conf },
{ nxt_nitems(nxt_perl_app_conf), nxt_perl_app_conf },
{ nxt_nitems(nxt_ruby_app_conf), nxt_ruby_app_conf },
{ nxt_nitems(nxt_java_app_conf), nxt_java_app_conf },
};

View File

@@ -164,6 +164,7 @@ NXT_EXPORT nxt_app_module_t nxt_app_module = {
compat,
nxt_string("php"),
PHP_VERSION,
NULL,
nxt_php_init,
};

View File

@@ -105,6 +105,7 @@ NXT_EXPORT nxt_app_module_t nxt_app_module = {
compat,
nxt_string("python"),
PY_VERSION,
NULL,
nxt_python_init,
};

View File

@@ -293,6 +293,7 @@ static const nxt_str_t *nxt_app_msg_prefix[] = {
&http_prefix,
&http_prefix,
&http_prefix,
&empty_prefix,
};

View File

@@ -113,6 +113,7 @@ NXT_EXPORT nxt_app_module_t nxt_app_module = {
nxt_perl_psgi_compat,
nxt_string("perl"),
PERL_VERSION_STRING,
NULL,
nxt_perl_psgi_init,
};

View File

@@ -76,6 +76,7 @@ NXT_EXPORT nxt_app_module_t nxt_app_module = {
compat,
nxt_string("ruby"),
ruby_version,
NULL,
nxt_ruby_init,
};

View File

@@ -0,0 +1,89 @@
import java.io.IOException;
import java.io.PrintWriter;
import javax.servlet.ServletConfig;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
@WebServlet("/")
public class app extends HttpServlet
{
@Override
public void doGet(HttpServletRequest request, HttpServletResponse response)
throws IOException, ServletException
{
if (request.getServletPath().equals("/1")) {
response.setContentType("text/plain;charset=utf-8");
response.setHeader("X-Character-Encoding", response.getCharacterEncoding());
response.setHeader("X-Content-Type", response.getContentType());
return;
}
if (request.getServletPath().equals("/2")) {
response.setContentType("text/plain");
response.setHeader("X-Character-Encoding", response.getCharacterEncoding());
response.setHeader("X-Content-Type", response.getContentType());
return;
}
if (request.getServletPath().equals("/3")) {
response.setContentType("text/plain;charset=utf-8");
response.setCharacterEncoding("windows-1251");
response.setHeader("X-Character-Encoding", response.getCharacterEncoding());
response.setHeader("X-Content-Type", response.getContentType());
return;
}
if (request.getServletPath().equals("/4")) {
response.setCharacterEncoding("windows-1251");
response.setContentType("text/plain");
response.setHeader("X-Character-Encoding", response.getCharacterEncoding());
response.setHeader("X-Content-Type", response.getContentType());
return;
}
if (request.getServletPath().equals("/5")) {
response.setContentType("text/plain;charset=utf-8");
response.setCharacterEncoding(null);
response.setHeader("X-Character-Encoding", response.getCharacterEncoding());
response.setHeader("X-Content-Type", response.getContentType());
return;
}
if (request.getServletPath().equals("/6")) {
response.setContentType("text/plain;charset=utf-8");
response.setContentType(null);
response.setHeader("X-Character-Encoding", response.getCharacterEncoding());
response.setHeader("X-Content-Type", response.getContentType());
return;
}
if (request.getServletPath().equals("/7")) {
response.setContentType("text/plain;charset=utf-8");
PrintWriter out = response.getWriter();
response.setCharacterEncoding("windows-1251");
response.setHeader("X-Character-Encoding", response.getCharacterEncoding());
response.setHeader("X-Content-Type", response.getContentType());
return;
}
if (request.getServletPath().equals("/8")) {
response.setContentType("text/plain;charset=utf-8");
PrintWriter out = response.getWriter();
response.setContentType("text/html;charset=windows-1251");
response.setHeader("X-Character-Encoding", response.getCharacterEncoding());
response.setHeader("X-Content-Type", response.getContentType());
return;
}
response.sendError(404);
}
}

View File

@@ -0,0 +1,30 @@
import java.io.IOException;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
@WebServlet(urlPatterns = "/")
public class app extends HttpServlet
{
@Override
public void doGet(HttpServletRequest request, HttpServletResponse response)
throws IOException, ServletException
{
Cookie[] cookies = request.getCookies();
if (cookies != null) {
for (Cookie c : cookies) {
if (c.getName().equals("var1")) {
response.addHeader("X-Cookie-1", c.getValue());
}
if (c.getName().equals("var2")) {
response.addHeader("X-Cookie-2", c.getValue());
}
}
}
}
}

18
test/java/empty/app.java Normal file
View File

@@ -0,0 +1,18 @@
import java.io.IOException;
import javax.servlet.ServletConfig;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
@WebServlet("/")
public class app extends HttpServlet
{
@Override
public void doGet(HttpServletRequest request, HttpServletResponse response)
throws IOException, ServletException
{ }
}

54
test/java/filter/app.java Normal file
View File

@@ -0,0 +1,54 @@
import java.io.IOException;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.annotation.WebFilter;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.FilterConfig;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
@WebServlet(urlPatterns = "/")
public class app extends HttpServlet
{
@WebFilter(urlPatterns = "")
public static class filter implements Filter
{
@Override
public void init(FilterConfig filterConfig)
{
}
@Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
throws IOException, ServletException
{
response.getOutputStream().println("Extra Info");
response.setCharacterEncoding("utf-8");
((HttpServletResponse) response).addHeader("X-Filter-Before", "1");
chain.doFilter(request, response);
((HttpServletResponse) response).setHeader("X-Filter-After", "1");
}
@Override
public void destroy()
{
}
}
@Override
public void doGet(HttpServletRequest request, HttpServletResponse response)
throws IOException, ServletException
{
response.getOutputStream().println("This is servlet response");
response.setHeader("X-Filter-After", "0");
}
}

138
test/java/forward/app.java Normal file
View File

@@ -0,0 +1,138 @@
import java.io.IOException;
import java.io.PrintWriter;
import java.util.Map;
import javax.servlet.DispatcherType;
import javax.servlet.RequestDispatcher;
import javax.servlet.ServletConfig;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletRequestWrapper;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpServletResponseWrapper;
public class app extends HttpServlet
{
private String id;
private class RequestWrapper extends HttpServletRequestWrapper
{
public RequestWrapper(HttpServletRequest r)
{
super(r);
}
}
private class ResponseWrapper extends HttpServletResponseWrapper
{
public ResponseWrapper(HttpServletResponse r)
{
super(r);
}
}
@Override
public void init(ServletConfig sc)
throws ServletException
{
id = sc.getInitParameter("id");
}
private RequestDispatcher getRequestDispatcher(HttpServletRequest request, String str)
{
String disp = request.getParameter("disp");
if (disp != null && disp.equals("ctx")) {
return request.getServletContext().getRequestDispatcher(str);
}
if (disp != null && disp.equals("name")) {
return request.getServletContext().getNamedDispatcher(str);
}
if (disp == null || disp.equals("req")) {
return request.getRequestDispatcher(str);
}
return null;
}
@Override
public void doGet(HttpServletRequest request, HttpServletResponse response)
throws IOException, ServletException
{
String dtype = "" + request.getDispatcherType();
response.addHeader("X-" + dtype + "-Id", id);
response.addHeader("X-" + dtype + "-Request-URI", "" + request.getRequestURI());
response.addHeader("X-" + dtype + "-Servlet-Path", "" + request.getServletPath());
response.addHeader("X-" + dtype + "-Path-Info", "" + request.getPathInfo());
response.addHeader("X-" + dtype + "-Query-String", "" + request.getQueryString());
response.addHeader("X-" + dtype + "-Dispatcher-Type", "" + request.getDispatcherType());
response.setContentType("text/plain; charset=utf-8");
Map<String, String[]> pmap = request.getParameterMap();
for (Map.Entry<String,String[]> p : pmap.entrySet()) {
response.addHeader("X-" + dtype + "-Param-" + p.getKey(), "" + String.join(",", p.getValue()));
}
PrintWriter out = response.getWriter();
if (id.equals("fwd")) {
String uri = request.getParameter("uri");
if (uri != null && request.getDispatcherType() != DispatcherType.FORWARD) {
response.addHeader("X-Forward-To", "" + uri);
out.println("Before forwarding.");
RequestDispatcher d = getRequestDispatcher(request, uri);
if (d == null) {
out.println("Dispatcher is null");
return;
}
try {
d.forward(new RequestWrapper(request), new ResponseWrapper(response));
} catch(Exception e) {
response.addHeader("X-Exception", "" + e);
}
response.addHeader("X-After-Forwarding", "you-should-not-see-this");
out.println("After forwarding.");
return;
}
}
if (id.equals("data")) {
response.addHeader("X-" + RequestDispatcher.FORWARD_REQUEST_URI, "" + request.getAttribute(RequestDispatcher.FORWARD_REQUEST_URI));
response.addHeader("X-" + RequestDispatcher.FORWARD_CONTEXT_PATH, "" + request.getAttribute(RequestDispatcher.FORWARD_CONTEXT_PATH));
response.addHeader("X-" + RequestDispatcher.FORWARD_SERVLET_PATH, "" + request.getAttribute(RequestDispatcher.FORWARD_SERVLET_PATH));
response.addHeader("X-" + RequestDispatcher.FORWARD_PATH_INFO, "" + request.getAttribute(RequestDispatcher.FORWARD_PATH_INFO));
response.addHeader("X-" + RequestDispatcher.FORWARD_QUERY_STRING, "" + request.getAttribute(RequestDispatcher.FORWARD_QUERY_STRING));
out.println("app.doGet(): #" + this + ", " + id);
out.println("RequestURI: " + request.getRequestURI());
out.println("ServletPath: " + request.getServletPath());
out.println("PathInfo: " + request.getPathInfo());
out.println("DispType: " + request.getDispatcherType());
out.println("QueryString: " + request.getQueryString());
for (Map.Entry<String,String[]> p : pmap.entrySet()) {
out.println("- " + p.getKey() + "=" + String.join(",", p.getValue()));
}
return;
}
response.sendError(404);
}
}

View File

@@ -0,0 +1 @@
<html><body>This is index.html.</body></html>

38
test/java/forward/web.xml Normal file
View File

@@ -0,0 +1,38 @@
<?xml version="1.0" encoding="utf-8" ?>
<web-app xmlns="http://java.sun.com/xml/ns/j2ee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/j2ee http://java.sun.com/xml/ns/j2ee/web-app_2_4.xsd"
version="3.0">
<servlet>
<servlet-name>fwd</servlet-name>
<servlet-class>app</servlet-class>
<init-param><param-name>id</param-name><param-value>fwd</param-value></init-param>
</servlet>
<servlet-mapping>
<servlet-name>fwd</servlet-name>
<url-pattern>/fwd/*</url-pattern>
</servlet-mapping>
<servlet>
<servlet-name>data</servlet-name>
<servlet-class>app</servlet-class>
<init-param><param-name>id</param-name><param-value>data</param-value></init-param>
</servlet>
<servlet-mapping>
<servlet-name>data</servlet-name>
<url-pattern>/data/*</url-pattern>
</servlet-mapping>
<servlet-mapping>
<servlet-name>data</servlet-name>
<url-pattern>/WEB-INF/index.html</url-pattern>
<url-pattern>/index.html</url-pattern>
</servlet-mapping>
</web-app>

View File

@@ -0,0 +1,21 @@
import java.io.IOException;
import java.io.PrintWriter;
import javax.servlet.ServletConfig;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
@WebServlet("/")
public class app extends HttpServlet
{
@Override
public void doGet(HttpServletRequest request, HttpServletResponse response)
throws IOException, ServletException
{
response.addHeader("X-Reply", request.getHeader("X-Header"));
}
}

View File

@@ -0,0 +1,27 @@
import java.io.IOException;
import java.io.PrintWriter;
import java.util.Enumeration;
import javax.servlet.ServletConfig;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
@WebServlet("/")
public class app extends HttpServlet
{
@Override
public void doGet(HttpServletRequest request, HttpServletResponse response)
throws IOException, ServletException
{
Enumeration<String> header_names = request.getHeaderNames();
for (int i = 0; header_names.hasMoreElements(); i++) {
response.addHeader("X-Reply-" + Integer.toString(i),
header_names.nextElement());
}
}
}

View File

@@ -0,0 +1,27 @@
import java.io.IOException;
import java.io.PrintWriter;
import java.util.Enumeration;
import javax.servlet.ServletConfig;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
@WebServlet("/")
public class app extends HttpServlet
{
@Override
public void doGet(HttpServletRequest request, HttpServletResponse response)
throws IOException, ServletException
{
Enumeration<String> headers = request.getHeaders("X-Header");
for (int i = 0; headers.hasMoreElements(); i++) {
response.addHeader("X-Reply-" + Integer.toString(i),
headers.nextElement());
}
}
}

View File

@@ -0,0 +1,50 @@
import java.io.IOException;
import java.util.Enumeration;
import java.util.Map;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
@WebServlet(urlPatterns = "/")
public class app extends HttpServlet
{
@Override
public void doGet(HttpServletRequest request, HttpServletResponse response)
throws IOException, ServletException
{
response.addHeader("X-Var-1", request.getParameter("var1"));
response.addHeader("X-Var-2", "" + (request.getParameter("var2") != null));
response.addHeader("X-Var-3", "" + (request.getParameter("var3") != null));
response.addHeader("X-Var-4", request.getParameter("var4"));
Enumeration<String> parameter_names = request.getParameterNames();
String names = "";
for (int i = 0; parameter_names.hasMoreElements(); i++) {
names = names.concat(parameter_names.nextElement() + " ");
}
response.addHeader("X-Param-Names", names);
String[] parameter_values = request.getParameterValues("var4");
String values = "";
for (int i = 0; i < parameter_values.length; i++) {
values = values.concat(parameter_values[i] + " ");
}
response.addHeader("X-Param-Values", values);
Map <String, String[]> parameter_map = request.getParameterMap();
String map = "";
for (Map.Entry <String, String[]> p : parameter_map.entrySet()) {
map = map.concat(p.getKey() + "=" + String.join(",", p.getValue()) + " ");
}
response.addHeader("X-Param-Map", map);
}
}

34
test/java/header/app.java Normal file
View File

@@ -0,0 +1,34 @@
import java.io.IOException;
import java.io.PrintWriter;
import javax.servlet.ServletConfig;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
@WebServlet("/")
public class app extends HttpServlet
{
@Override
public void doGet(HttpServletRequest request, HttpServletResponse response)
throws IOException, ServletException
{
response.setHeader("X-Set-Utf8-Value", "тест");
response.setHeader("X-Set-Utf8-Name-Имя", "x");
response.addHeader("X-Add-Utf8-Value", "тест");
response.addHeader("X-Add-Utf8-Name-Имя", "y");
response.addHeader("X-Add-Test", "v1");
response.addHeader("X-Add-Test", null);
response.setHeader("X-Set-Test1", "v1");
response.setHeader("X-Set-Test1", null);
response.setHeader("X-Set-Test2", "v1");
response.setHeader("X-Set-Test2", "");
}
}

View File

@@ -0,0 +1,22 @@
import java.io.IOException;
import java.io.PrintWriter;
import javax.servlet.ServletConfig;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
@WebServlet("/")
public class app extends HttpServlet
{
@Override
public void doGet(HttpServletRequest request, HttpServletResponse response)
throws IOException, ServletException
{
response.setDateHeader("X-Set-Date", 1000);
response.addDateHeader("X-Get-Date", request.getDateHeader("X-Header"));
}
}

View File

@@ -0,0 +1,22 @@
import java.io.IOException;
import java.io.PrintWriter;
import javax.servlet.ServletConfig;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
@WebServlet("/")
public class app extends HttpServlet
{
@Override
public void doGet(HttpServletRequest request, HttpServletResponse response)
throws IOException, ServletException
{
response.setIntHeader("X-Set-Int", 1);
response.addHeader("X-Get-Int", Integer.toString(request.getIntHeader("X-Header")));
}
}

136
test/java/include/app.java Normal file
View File

@@ -0,0 +1,136 @@
import java.io.IOException;
import java.io.PrintWriter;
import java.util.Map;
import javax.servlet.DispatcherType;
import javax.servlet.RequestDispatcher;
import javax.servlet.ServletConfig;
import javax.servlet.ServletException;
import javax.servlet.ServletOutputStream;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletRequestWrapper;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpServletResponseWrapper;
public class app extends HttpServlet
{
private String id;
private class RequestWrapper extends HttpServletRequestWrapper
{
public RequestWrapper(HttpServletRequest r)
{
super(r);
}
}
private class ResponseWrapper extends HttpServletResponseWrapper
{
public ResponseWrapper(HttpServletResponse r)
{
super(r);
}
}
@Override
public void init(ServletConfig sc)
throws ServletException
{
id = sc.getInitParameter("id");
}
private RequestDispatcher getRequestDispatcher(HttpServletRequest request, String str)
{
String disp = request.getParameter("disp");
if (disp != null && disp.equals("ctx")) {
return request.getServletContext().getRequestDispatcher(str);
}
if (disp != null && disp.equals("name")) {
return request.getServletContext().getNamedDispatcher(str);
}
if (disp == null || disp.equals("req")) {
return request.getRequestDispatcher(str);
}
return null;
}
@Override
public void doGet(HttpServletRequest request, HttpServletResponse response)
throws IOException, ServletException
{
String dtype = "" + request.getDispatcherType();
response.addHeader("X-" + dtype + "-Id", id);
response.addHeader("X-" + dtype + "-Request-URI", "" + request.getRequestURI());
response.addHeader("X-" + dtype + "-Servlet-Path", "" + request.getServletPath());
response.addHeader("X-" + dtype + "-Path-Info", "" + request.getPathInfo());
response.addHeader("X-" + dtype + "-Query-String", "" + request.getQueryString());
response.addHeader("X-" + dtype + "-Dispatcher-Type", "" + request.getDispatcherType());
response.setContentType("text/plain; charset=utf-8");
PrintWriter out = response.getWriter();
if (id.equals("inc")) {
String uri = request.getParameter("uri");
if (uri != null && request.getDispatcherType() != DispatcherType.INCLUDE) {
response.addHeader("X-Include", "" + uri);
out.println("Before include.");
RequestDispatcher d = getRequestDispatcher(request, uri);
if (d == null) {
out.println("Dispatcher is null");
return;
}
try {
d.include(new RequestWrapper(request), new ResponseWrapper(response));
} catch(Exception e) {
response.addHeader("X-Exception", "" + e);
out.println("Exception: " + e);
}
response.addHeader("X-After-Include", "you-should-see-this");
out.println("After include.");
return;
}
}
if (id.equals("data")) {
out.println("app.doGet(): #" + this + ", " + id);
out.println("RequestURI: " + request.getRequestURI());
out.println("ServletPath: " + request.getServletPath());
out.println("PathInfo: " + request.getPathInfo());
out.println("DispType: " + request.getDispatcherType());
out.println("QueryString: " + request.getQueryString());
Map<String, String[]> pmap = request.getParameterMap();
for (Map.Entry<String,String[]> p : pmap.entrySet()) {
out.println("- " + p.getKey() + "=" + String.join(",", p.getValue()));
}
out.println(RequestDispatcher.INCLUDE_REQUEST_URI + ": " + request.getAttribute(RequestDispatcher.INCLUDE_REQUEST_URI));
out.println(RequestDispatcher.INCLUDE_CONTEXT_PATH + ": " + request.getAttribute(RequestDispatcher.INCLUDE_CONTEXT_PATH));
out.println(RequestDispatcher.INCLUDE_SERVLET_PATH + ": " + request.getAttribute(RequestDispatcher.INCLUDE_SERVLET_PATH));
out.println(RequestDispatcher.INCLUDE_PATH_INFO + ": " + request.getAttribute(RequestDispatcher.INCLUDE_PATH_INFO));
out.println(RequestDispatcher.INCLUDE_QUERY_STRING + ": " + request.getAttribute(RequestDispatcher.INCLUDE_QUERY_STRING));
return;
}
response.sendError(404);
}
}

View File

@@ -0,0 +1 @@
<html><body>This is index.html.</body></html>

37
test/java/include/web.xml Normal file
View File

@@ -0,0 +1,37 @@
<?xml version="1.0" encoding="utf-8" ?>
<web-app xmlns="http://java.sun.com/xml/ns/j2ee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/j2ee http://java.sun.com/xml/ns/j2ee/web-app_2_4.xsd"
version="3.0">
<servlet>
<servlet-name>inc</servlet-name>
<servlet-class>app</servlet-class>
<init-param><param-name>id</param-name><param-value>inc</param-value></init-param>
</servlet>
<servlet>
<servlet-name>data</servlet-name>
<servlet-class>app</servlet-class>
<init-param><param-name>id</param-name><param-value>data</param-value></init-param>
</servlet>
<servlet-mapping>
<servlet-name>inc</servlet-name>
<url-pattern>/inc/*</url-pattern>
</servlet-mapping>
<servlet-mapping>
<servlet-name>data</servlet-name>
<url-pattern>/data/*</url-pattern>
</servlet-mapping>
<servlet-mapping>
<servlet-name>data</servlet-name>
<url-pattern>/WEB-INF/index.html</url-pattern>
<url-pattern>/index.html</url-pattern>
</servlet-mapping>
</web-app>

2
test/java/jsp/index.jsp Normal file
View File

@@ -0,0 +1,2 @@
<%@ page contentType="text/plain"%>This is plain text response for "<%= request.getMethod() %> <%= request.getRequestURI() %>".
<% response.addHeader("X-Unit-JSP", "ok"); %>

37
test/java/mirror/app.java Normal file
View File

@@ -0,0 +1,37 @@
import java.io.*;
import javax.servlet.ServletConfig;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
@WebServlet("/")
public class app extends HttpServlet
{
@Override
public void doPost(HttpServletRequest request, HttpServletResponse response)
throws IOException, ServletException
{
StringBuilder buffer = new StringBuilder();
BufferedReader reader = request.getReader();
String line;
while ((line = reader.readLine()) != null) {
buffer.append(line);
}
String data = buffer.toString();
String dataLength = Integer.toString(data.length());
response.setHeader("Content-Length", dataLength);
response.setContentType("text/html");
PrintWriter out = response.getWriter();
out.print(data);
out.flush();
}
}

View File

@@ -0,0 +1,56 @@
import java.io.IOException;
import java.io.PrintWriter;
import java.io.InputStream;
import java.util.Set;
import javax.servlet.ServletConfig;
import javax.servlet.ServletContext;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
@WebServlet( urlPatterns = { "/", "/pt/*" } )
public class app extends HttpServlet
{
@Override
public void doGet(HttpServletRequest request, HttpServletResponse response)
throws IOException, ServletException
{
response.addHeader("X-Request-URI", "" + request.getRequestURI());
response.addHeader("X-Servlet-Path", "" + request.getServletPath());
response.addHeader("X-Path-Info", "" + request.getPathInfo());
response.addHeader("X-Query-String", "" + request.getQueryString());
response.addHeader("X-Path-Translated", "" + request.getPathTranslated());
response.setContentType("text/plain; charset=utf-8");
PrintWriter out = response.getWriter();
ServletContext ctx = request.getServletContext();
String path = request.getParameter("path");
if (path != null) {
response.addHeader("X-Real-Path", "" + ctx.getRealPath(path));
response.addHeader("X-Resource", "" + ctx.getResource(path));
Set<String> paths = ctx.getResourcePaths(path);
response.addHeader("X-Resource-Paths", "" + paths);
InputStream is = ctx.getResourceAsStream(path);
response.addHeader("X-Resource-As-Stream", "" + is);
if (is != null) {
final byte[] buf = new byte[1024];
int r = is.read(buf);
out.println(new String(buf, 0, r, "utf-8"));
}
}
}
}

View File

@@ -0,0 +1 @@
<html><body>This is index.html.</body></html>

View File

@@ -0,0 +1,22 @@
import java.io.IOException;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
@WebServlet(urlPatterns = "/")
public class app extends HttpServlet
{
@Override
public void doPost(HttpServletRequest request, HttpServletResponse response)
throws IOException, ServletException
{
response.addHeader("X-Var-1", request.getParameter("var1"));
response.addHeader("X-Var-2", "" + (request.getParameter("var2") != null));
response.addHeader("X-Var-3", "" + (request.getParameter("var3") != null));
}
}

View File

@@ -0,0 +1,20 @@
import java.io.IOException;
import javax.servlet.ServletConfig;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
@WebServlet( urlPatterns = { "/" } )
public class app extends HttpServlet
{
@Override
public void doGet(HttpServletRequest request, HttpServletResponse response)
throws IOException, ServletException
{
response.addHeader("X-Query-String", "" + request.getQueryString());
}
}

View File

@@ -0,0 +1,79 @@
import java.io.IOException;
import javax.servlet.ServletException;
import javax.servlet.ServletRequestEvent;
import javax.servlet.ServletRequestListener;
import javax.servlet.ServletRequestAttributeEvent;
import javax.servlet.ServletRequestAttributeListener;
import javax.servlet.annotation.WebServlet;
import javax.servlet.annotation.WebListener;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
@WebListener
@WebServlet(urlPatterns = "/")
public class app extends HttpServlet implements
ServletRequestListener,
ServletRequestAttributeListener
{
private static String request_initialized = "";
private static String request_destroyed = "";
private static String attribute_added = "";
private static String attribute_removed = "";
private static String attribute_replaced = "";
@Override
public void requestInitialized(ServletRequestEvent sre)
{
HttpServletRequest r = (HttpServletRequest) sre.getServletRequest();
request_initialized = r.getRequestURI();
}
@Override
public void requestDestroyed(ServletRequestEvent sre)
{
HttpServletRequest r = (HttpServletRequest) sre.getServletRequest();
request_destroyed = r.getRequestURI();
attribute_added = "";
attribute_removed = "";
attribute_replaced = "";
}
@Override
public void attributeAdded(ServletRequestAttributeEvent event)
{
attribute_added += event.getName() + "=" + event.getValue() + ";";
}
@Override
public void attributeRemoved(ServletRequestAttributeEvent event)
{
attribute_removed += event.getName() + "=" + event.getValue() + ";";
}
@Override
public void attributeReplaced(ServletRequestAttributeEvent event)
{
attribute_replaced += event.getName() + "=" + event.getValue() + ";";
}
@Override
public void doGet(HttpServletRequest request, HttpServletResponse response)
throws IOException, ServletException
{
request.setAttribute("var", request.getParameter("var1"));
request.setAttribute("var", request.getParameter("var2"));
request.setAttribute("var", request.getParameter("var3"));
response.addHeader("X-Request-Initialized", request_initialized);
response.addHeader("X-Request-Destroyed", request_destroyed);
response.addHeader("X-Attr-Added", attribute_added);
response.addHeader("X-Attr-Removed", attribute_removed);
response.addHeader("X-Attr-Replaced", attribute_replaced);
}
}

View File

@@ -0,0 +1,30 @@
import java.io.IOException;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
@WebServlet(urlPatterns = "/")
public class app extends HttpServlet
{
@Override
public void doGet(HttpServletRequest request, HttpServletResponse response)
throws IOException, ServletException
{
HttpSession s = request.getSession();
String old_var1 = (String) s.getAttribute("var1");
s.setAttribute("var1", request.getParameter("var1"));
if (old_var1 == null) {
response.addHeader("X-Var-1", "null");
} else {
response.addHeader("X-Var-1", old_var1);
}
response.addHeader("X-Session-Id", s.getId());
response.addHeader("X-Session-New", "" + s.isNew());
}
}

View File

@@ -0,0 +1,27 @@
import java.io.IOException;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
@WebServlet(urlPatterns = "/")
public class app extends HttpServlet
{
@Override
public void doGet(HttpServletRequest request, HttpServletResponse response)
throws IOException, ServletException
{
HttpSession s = request.getSession();
if (s.isNew()) {
s.setMaxInactiveInterval(2);
}
response.addHeader("X-Session-Id", s.getId());
response.addDateHeader("X-Session-Last-Access-Time", s.getLastAccessedTime());
response.addIntHeader("X-Session-Interval", s.getMaxInactiveInterval());
}
}

View File

@@ -0,0 +1,23 @@
import java.io.IOException;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
@WebServlet(urlPatterns = "/")
public class app extends HttpServlet
{
@Override
public void doGet(HttpServletRequest request, HttpServletResponse response)
throws IOException, ServletException
{
HttpSession s = request.getSession();
s.invalidate();
response.addHeader("X-Session-Id", s.getId());
}
}

View File

@@ -0,0 +1,80 @@
import java.io.IOException;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
import javax.servlet.http.HttpSessionAttributeListener;
import javax.servlet.http.HttpSessionBindingEvent;
import javax.servlet.http.HttpSessionEvent;
import javax.servlet.http.HttpSessionIdListener;
import javax.servlet.http.HttpSessionListener;
@WebServlet(urlPatterns = "/")
public class app extends HttpServlet implements
HttpSessionListener,
HttpSessionIdListener,
HttpSessionAttributeListener
{
private static String session_created = "";
private static String session_destroyed = "";
private static String session_id_changed = "";
private static String attribute_added = "";
private static String attribute_removed = "";
private static String attribute_replaced = "";
@Override
public void sessionCreated(HttpSessionEvent se)
{
session_created += se.getSession().getId();
}
@Override
public void sessionDestroyed(HttpSessionEvent se)
{
session_destroyed += se.getSession().getId();
}
@Override
public void sessionIdChanged(HttpSessionEvent event, String oldId)
{
session_id_changed += " " + oldId + "->" + event.getSession().getId();
}
@Override
public void attributeAdded(HttpSessionBindingEvent event)
{
attribute_added += event.getName() + "=" + event.getValue();
}
@Override
public void attributeRemoved(HttpSessionBindingEvent event)
{
attribute_removed += event.getName() + "=" + event.getValue();
}
@Override
public void attributeReplaced(HttpSessionBindingEvent event)
{
attribute_replaced += event.getName() + "=" + event.getValue();
}
@Override
public void doGet(HttpServletRequest request, HttpServletResponse response)
throws IOException, ServletException
{
HttpSession s = request.getSession();
s.setAttribute("var1", request.getParameter("var1"));
response.addHeader("X-Session-Id", s.getId());
response.addHeader("X-Session-Created", session_created);
response.addHeader("X-Session-Destroyed", session_destroyed);
response.addHeader("X-Attr-Added", attribute_added);
response.addHeader("X-Attr-Removed", attribute_removed);
response.addHeader("X-Attr-Replaced", attribute_replaced);
}
}

View File

@@ -0,0 +1,14 @@
<?xml version="1.0" encoding="utf-8" ?>
<web-app xmlns="http://java.sun.com/xml/ns/j2ee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/j2ee http://java.sun.com/xml/ns/j2ee/web-app_2_4.xsd"
version="3.0">
<listener>
<listener-class>app</listener-class>
</listener>
<listener>
<listener-class>app</listener-class>
</listener>
</web-app>

View File

@@ -0,0 +1,39 @@
import java.io.IOException;
import java.io.PrintWriter;
import javax.servlet.ServletConfig;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
public class app extends HttpServlet
{
private String id;
@Override
public void init(ServletConfig sc)
throws ServletException
{
id = sc.getInitParameter("id");
}
@Override
public void doGet(HttpServletRequest request, HttpServletResponse response)
throws IOException, ServletException
{
response.addHeader("X-Id", id);
response.addHeader("X-Request-URI", "" + request.getRequestURI());
response.addHeader("X-Servlet-Path", "" + request.getServletPath());
response.setHeader("X-Path-Info", "" + request.getPathInfo());
response.setContentType("text/plain; charset=utf-8");
PrintWriter out = response.getWriter();
out.println("app.doGet(): #" + this + ", " + id);
out.println("RequestURI: " + request.getRequestURI());
out.println("ServletPath: " + request.getServletPath());
out.println("PathInfo: " + request.getPathInfo());
}
}

View File

@@ -0,0 +1,75 @@
<?xml version="1.0" encoding="utf-8" ?>
<web-app xmlns="http://java.sun.com/xml/ns/j2ee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/j2ee http://java.sun.com/xml/ns/j2ee/web-app_2_4.xsd"
version="3.0">
<servlet>
<servlet-name>servlet0</servlet-name>
<servlet-class>app</servlet-class>
<init-param><param-name>id</param-name><param-value>servlet0</param-value></init-param>
</servlet>
<servlet>
<servlet-name>servlet1</servlet-name>
<servlet-class>app</servlet-class>
<init-param><param-name>id</param-name><param-value>servlet1</param-value></init-param>
</servlet>
<servlet>
<servlet-name>servlet2</servlet-name>
<servlet-class>app</servlet-class>
<init-param><param-name>id</param-name><param-value>servlet2</param-value></init-param>
</servlet>
<servlet>
<servlet-name>servlet3</servlet-name>
<servlet-class>app</servlet-class>
<init-param><param-name>id</param-name><param-value>servlet3</param-value></init-param>
</servlet>
<servlet>
<servlet-name>servlet4</servlet-name>
<servlet-class>app</servlet-class>
<init-param><param-name>id</param-name><param-value>servlet4</param-value></init-param>
</servlet>
<servlet>
<servlet-name>default</servlet-name>
<servlet-class>app</servlet-class>
<init-param><param-name>id</param-name><param-value>default</param-value></init-param>
</servlet>
<servlet-mapping>
<servlet-name>servlet0</servlet-name>
<url-pattern>/foo/*</url-pattern>
</servlet-mapping>
<servlet-mapping>
<servlet-name>servlet1</servlet-name>
<url-pattern>/foo/bar/*</url-pattern>
</servlet-mapping>
<servlet-mapping>
<servlet-name>servlet2</servlet-name>
<url-pattern>/baz/*</url-pattern>
</servlet-mapping>
<servlet-mapping>
<servlet-name>servlet3</servlet-name>
<url-pattern>/catalog</url-pattern>
</servlet-mapping>
<servlet-mapping>
<servlet-name>servlet4</servlet-name>
<url-pattern>*.bop</url-pattern>
</servlet-mapping>
<servlet-mapping>
<servlet-name>default</servlet-name>
<url-pattern>/</url-pattern>
</servlet-mapping>
</web-app>

View File

@@ -0,0 +1,67 @@
import java.io.IOException;
import java.io.PrintWriter;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.annotation.WebFilter;
import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.FilterConfig;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
public class app extends HttpServlet
{
@WebFilter(urlPatterns = "*.jsp")
public static class jsp_filter implements Filter
{
@Override
public void init(FilterConfig filterConfig) { }
@Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
throws IOException, ServletException
{
((HttpServletResponse) response).addHeader("X-JSP-Filter", "1");
chain.doFilter(request, response);
}
@Override
public void destroy() { }
}
@WebFilter(urlPatterns = "*.txt")
public static class txt_filter implements Filter
{
@Override
public void init(FilterConfig filterConfig) { }
@Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
throws IOException, ServletException
{
((HttpServletResponse) response).addHeader("X-TXT-Filter", "1");
chain.doFilter(request, response);
}
@Override
public void destroy() { }
}
@Override
public void doGet(HttpServletRequest request, HttpServletResponse response)
throws IOException, ServletException
{
response.addHeader("X-App-Servlet", "1");
response.setContentType("text/plain; charset=utf-8");
PrintWriter out = response.getWriter();
out.println("App Servlet");
}
}

View File

@@ -0,0 +1 @@
This is index.txt.

View File

@@ -0,0 +1,3 @@
<%@ page contentType="text/html"%>
<html><body><p>You should see this on <a href="/dir2/">/dir2/</a> URL.</p></body></html>
<% response.addHeader("X-Unit-JSP", "ok"); %>

View File

@@ -0,0 +1 @@
<html><body><p>You should see this on <a href="/dir2/">/dir2/</a> URL.</p></body></html>

View File

@@ -0,0 +1 @@
You should never see this.

View File

@@ -0,0 +1 @@
<html><body><p>You should see this for <a href="/dir4/index.html">/dir4/index.html</a> or <a href="/dir4/">/dir4/</a> url.</body></html>

View File

@@ -0,0 +1 @@
<html><body><p>You should see this ONLY for <a href="/index.htm">/index.htm</a> url.</body></html>

View File

@@ -0,0 +1,27 @@
<?xml version="1.0" encoding="utf-8" ?>
<web-app xmlns="http://java.sun.com/xml/ns/j2ee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/j2ee http://java.sun.com/xml/ns/j2ee/web-app_2_4.xsd"
version="3.0">
<welcome-file-list>
<welcome-file>index.txt</welcome-file>
<welcome-file>default.jsp</welcome-file>
<welcome-file>index.html</welcome-file>
</welcome-file-list>
<servlet>
<servlet-name>app</servlet-name>
<servlet-class>app</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>app</servlet-name>
<url-pattern>/dir3/index.txt</url-pattern>
<url-pattern>/dir4/index.txt</url-pattern>
<url-pattern>/dir5/index.html</url-pattern>
</servlet-mapping>
</web-app>

View File

@@ -0,0 +1,753 @@
import time
import unittest
import unit
class TestUnitJavaApplication(unit.TestUnitApplicationJava):
def setUpClass():
unit.TestUnit().check_modules('java')
def test_java_application_cookies(self):
self.load('cookies')
headers = self.get(headers={
'Cookie': 'var1=val1; var2=val2',
'Host': 'localhost',
'Connection': 'close'
})['headers']
self.assertEqual(headers['X-Cookie-1'], 'val1', 'cookie 1')
self.assertEqual(headers['X-Cookie-2'], 'val2', 'cookie 2')
def test_java_application_filter(self):
self.load('filter')
headers = self.get()['headers']
self.assertEqual(headers['X-Filter-Before'], '1', 'filter before')
self.assertEqual(headers['X-Filter-After'], '1', 'filter after')
self.assertEqual(self.get(url='/test')['headers']['X-Filter-After'],
'0', 'filter after 2')
def test_java_application_get_variables(self):
self.load('get_params')
headers = self.get(url='/?var1=val1&var2=&var4=val4&var4=foo')['headers']
self.assertEqual(headers['X-Var-1'], 'val1', 'GET variables')
self.assertEqual(headers['X-Var-2'], 'true', 'GET variables 2')
self.assertEqual(headers['X-Var-3'], 'false', 'GET variables 3')
self.assertEqual(headers['X-Param-Names'], 'var4 var2 var1 ',
'getParameterNames')
self.assertEqual(headers['X-Param-Values'], 'val4 foo ',
'getParameterValues')
self.assertEqual(headers['X-Param-Map'],
'var2= var1=val1 var4=val4,foo ', 'getParameterMap')
def test_java_application_post_variables(self):
self.load('post_params')
headers = self.post(headers={
'Content-Type': 'application/x-www-form-urlencoded',
'Host': 'localhost',
'Connection': 'close'
}, body='var1=val1&var2=')['headers']
self.assertEqual(headers['X-Var-1'], 'val1', 'POST variables')
self.assertEqual(headers['X-Var-2'], 'true', 'POST variables 2')
self.assertEqual(headers['X-Var-3'], 'false', 'POST variables 3')
def test_java_application_session(self):
self.load('session')
headers = self.get(url='/?var1=val1')['headers']
session_id = headers['X-Session-Id']
self.assertEqual(headers['X-Var-1'], 'null', 'variable empty')
self.assertEqual(headers['X-Session-New'], 'true', 'session create')
headers = self.get(headers={
'Host': 'localhost',
'Cookie': 'JSESSIONID=' + session_id,
'Connection': 'close'
}, url='/?var1=val2')['headers']
self.assertEqual(headers['X-Var-1'], 'val1', 'variable')
self.assertEqual(headers['X-Session-New'], 'false', 'session resume')
self.assertEqual(session_id, headers['X-Session-Id'], 'session same id')
def test_java_application_session_active(self):
self.load('session_inactive')
resp = self.get()
session_id = resp['headers']['X-Session-Id']
self.assertEqual(resp['status'], 200, 'session init')
self.assertEqual(resp['headers']['X-Session-Interval'], '2',
'session interval')
self.assertLess(abs(self.date_to_sec_epoch(
resp['headers']['X-Session-Last-Access-Time']) - self.sec_epoch()),
5, 'session last access time')
time.sleep(1)
resp = self.get(headers={
'Host': 'localhost',
'Cookie': 'JSESSIONID=' + session_id,
'Connection': 'close'
})
self.assertEqual(resp['headers']['X-Session-Id'], session_id,
'session active')
session_id = resp['headers']['X-Session-Id']
time.sleep(1)
resp = self.get(headers={
'Host': 'localhost',
'Cookie': 'JSESSIONID=' + session_id,
'Connection': 'close'
})
self.assertEqual(resp['headers']['X-Session-Id'], session_id,
'session active 2')
time.sleep(1)
resp = self.get(headers={
'Host': 'localhost',
'Cookie': 'JSESSIONID=' + session_id,
'Connection': 'close'
})
self.assertEqual(resp['headers']['X-Session-Id'], session_id,
'session active 3')
def test_java_application_session_inactive(self):
self.load('session_inactive')
resp = self.get()
session_id = resp['headers']['X-Session-Id']
time.sleep(3)
resp = self.get(headers={
'Host': 'localhost',
'Cookie': 'JSESSIONID=' + session_id,
'Connection': 'close'
})
self.assertNotEqual(resp['headers']['X-Session-Id'], session_id,
'session inactive')
def test_java_application_session_invalidate(self):
self.load('session_invalidate')
resp = self.get()
session_id = resp['headers']['X-Session-Id']
resp = self.get(headers={
'Host': 'localhost',
'Cookie': 'JSESSIONID=' + session_id,
'Connection': 'close'
})
self.assertNotEqual(resp['headers']['X-Session-Id'], session_id,
'session invalidate')
def test_java_application_session_listeners(self):
self.load('session_listeners')
headers = self.get(url='/test?var1=val1')['headers']
session_id = headers['X-Session-Id']
self.assertEqual(headers['X-Session-Created'], session_id,
'session create')
self.assertEqual(headers['X-Attr-Added'], 'var1=val1',
'attribute add')
headers = self.get(headers={
'Host': 'localhost',
'Cookie': 'JSESSIONID=' + session_id,
'Connection': 'close'
}, url='/?var1=val2')['headers']
self.assertEqual(session_id, headers['X-Session-Id'], 'session same id')
self.assertEqual(headers['X-Attr-Replaced'], 'var1=val1',
'attribute replace')
headers = self.get(headers={
'Host': 'localhost',
'Cookie': 'JSESSIONID=' + session_id,
'Connection': 'close'
}, url='/')['headers']
self.assertEqual(session_id, headers['X-Session-Id'], 'session same id')
self.assertEqual(headers['X-Attr-Removed'], 'var1=val2',
'attribute remove')
def test_java_application_jsp(self):
self.load('jsp')
headers = self.get(url='/index.jsp')['headers']
self.assertEqual(headers['X-Unit-JSP'], 'ok', 'JSP Ok header')
def test_java_application_url_pattern(self):
self.load('url_pattern')
headers = self.get(url='/foo/bar/index.html')['headers']
self.assertEqual(headers['X-Id'], 'servlet1', '#1 Servlet1 request')
self.assertEqual(headers['X-Request-URI'], '/foo/bar/index.html', '#1 request URI')
self.assertEqual(headers['X-Servlet-Path'], '/foo/bar', '#1 servlet path')
self.assertEqual(headers['X-Path-Info'], '/index.html', '#1 path info')
headers = self.get(url='/foo/bar/index.bop')['headers']
self.assertEqual(headers['X-Id'], 'servlet1', '#2 Servlet1 request')
self.assertEqual(headers['X-Request-URI'], '/foo/bar/index.bop', '#2 request URI')
self.assertEqual(headers['X-Servlet-Path'], '/foo/bar', '#2 servlet path')
self.assertEqual(headers['X-Path-Info'], '/index.bop', '#2 path info')
headers = self.get(url='/baz')['headers']
self.assertEqual(headers['X-Id'], 'servlet2', '#3 Servlet2 request')
self.assertEqual(headers['X-Request-URI'], '/baz', '#3 request URI')
self.assertEqual(headers['X-Servlet-Path'], '/baz', '#3 servlet path')
self.assertEqual(headers['X-Path-Info'], 'null', '#3 path info')
headers = self.get(url='/baz/index.html')['headers']
self.assertEqual(headers['X-Id'], 'servlet2', '#4 Servlet2 request')
self.assertEqual(headers['X-Request-URI'], '/baz/index.html', '#4 request URI')
self.assertEqual(headers['X-Servlet-Path'], '/baz', '#4 servlet path')
self.assertEqual(headers['X-Path-Info'], '/index.html', '#4 path info')
headers = self.get(url='/catalog')['headers']
self.assertEqual(headers['X-Id'], 'servlet3', '#5 Servlet3 request')
self.assertEqual(headers['X-Request-URI'], '/catalog', '#5 request URI')
self.assertEqual(headers['X-Servlet-Path'], '/catalog', '#5 servlet path')
self.assertEqual(headers['X-Path-Info'], 'null', '#5 path info')
headers = self.get(url='/catalog/index.html')['headers']
self.assertEqual(headers['X-Id'], 'default', '#6 default request')
self.assertEqual(headers['X-Request-URI'], '/catalog/index.html', '#6 request URI')
self.assertEqual(headers['X-Servlet-Path'], '/catalog/index.html', '#6 servlet path')
self.assertEqual(headers['X-Path-Info'], 'null', '#6 path info')
headers = self.get(url='/catalog/racecar.bop')['headers']
self.assertEqual(headers['X-Id'], 'servlet4', '#7 servlet4 request')
self.assertEqual(headers['X-Request-URI'], '/catalog/racecar.bop', '#7 request URI')
self.assertEqual(headers['X-Servlet-Path'], '/catalog/racecar.bop', '#7 servlet path')
self.assertEqual(headers['X-Path-Info'], 'null', '#7 path info')
headers = self.get( url='/index.bop')['headers']
self.assertEqual(headers['X-Id'], 'servlet4', '#8 servlet4 request')
self.assertEqual(headers['X-Request-URI'], '/index.bop', '#8 request URI')
self.assertEqual(headers['X-Servlet-Path'], '/index.bop', '#8 servlet path')
self.assertEqual(headers['X-Path-Info'], 'null', '#8 path info')
headers = self.get(url='/foo/baz')['headers']
self.assertEqual(headers['X-Id'], 'servlet0', '#9 servlet0 request')
self.assertEqual(headers['X-Request-URI'], '/foo/baz', '#9 request URI')
self.assertEqual(headers['X-Servlet-Path'], '/foo', '#9 servlet path')
self.assertEqual(headers['X-Path-Info'], '/baz', '#9 path info')
headers = self.get()['headers']
self.assertEqual(headers['X-Id'], 'default', '#10 default request')
self.assertEqual(headers['X-Request-URI'], '/', '#10 request URI')
self.assertEqual(headers['X-Servlet-Path'], '/', '#10 servlet path')
self.assertEqual(headers['X-Path-Info'], 'null', '#10 path info')
headers = self.get(url='/index.bop/')['headers']
self.assertEqual(headers['X-Id'], 'default', '#11 default request')
self.assertEqual(headers['X-Request-URI'], '/index.bop/', '#11 request URI')
self.assertEqual(headers['X-Servlet-Path'], '/index.bop/', '#11 servlet path')
self.assertEqual(headers['X-Path-Info'], 'null', '#11 path info')
def test_java_application_header(self):
self.load('header')
headers = self.get()['headers']
self.assertEqual(headers['X-Set-Utf8-Value'], '????', 'set Utf8 header value')
self.assertEqual(headers['X-Set-Utf8-Name-???'], 'x', 'set Utf8 header name')
self.assertEqual(headers['X-Add-Utf8-Value'], '????', 'add Utf8 header value')
self.assertEqual(headers['X-Add-Utf8-Name-???'], 'y', 'add Utf8 header name')
self.assertEqual(headers['X-Add-Test'], 'v1', 'add null header')
self.assertEqual('X-Set-Test1' in headers, False, 'set null header')
self.assertEqual(headers['X-Set-Test2'], '', 'set empty header')
def test_java_application_content_type(self):
self.load('content_type')
headers = self.get(url='/1')['headers']
self.assertEqual(headers['Content-Type'], 'text/plain;charset=utf-8', '#1 Content-Type header')
self.assertEqual(headers['X-Content-Type'], 'text/plain;charset=utf-8', '#1 response Content-Type')
self.assertEqual(headers['X-Character-Encoding'], 'utf-8', '#1 response charset')
headers = self.get(url='/2')['headers']
self.assertEqual(headers['Content-Type'], 'text/plain;charset=iso-8859-1', '#2 Content-Type header')
self.assertEqual(headers['X-Content-Type'], 'text/plain;charset=iso-8859-1', '#2 response Content-Type')
self.assertEqual(headers['X-Character-Encoding'], 'iso-8859-1', '#2 response charset')
headers = self.get(url='/3')['headers']
self.assertEqual(headers['Content-Type'], 'text/plain;charset=windows-1251', '#3 Content-Type header')
self.assertEqual(headers['X-Content-Type'], 'text/plain;charset=windows-1251', '#3 response Content-Type')
self.assertEqual(headers['X-Character-Encoding'], 'windows-1251', '#3 response charset')
headers = self.get(url='/4')['headers']
self.assertEqual(headers['Content-Type'], 'text/plain;charset=windows-1251', '#4 Content-Type header')
self.assertEqual(headers['X-Content-Type'], 'text/plain;charset=windows-1251', '#4 response Content-Type')
self.assertEqual(headers['X-Character-Encoding'], 'windows-1251', '#4 response charset')
headers = self.get(url='/5')['headers']
self.assertEqual(headers['Content-Type'], 'text/plain;charset=iso-8859-1', '#5 Content-Type header')
self.assertEqual(headers['X-Content-Type'], 'text/plain;charset=iso-8859-1', '#5 response Content-Type')
self.assertEqual(headers['X-Character-Encoding'], 'iso-8859-1', '#5 response charset')
headers = self.get(url='/6')['headers']
self.assertEqual('Content-Type' in headers, False, '#6 no Content-Type header')
self.assertEqual('X-Content-Type' in headers, False, '#6 no response Content-Type')
self.assertEqual(headers['X-Character-Encoding'], 'utf-8', '#6 response charset')
headers = self.get(url='/7')['headers']
self.assertEqual(headers['Content-Type'], 'text/plain;charset=utf-8', '#7 Content-Type header')
self.assertEqual(headers['X-Content-Type'], 'text/plain;charset=utf-8', '#7 response Content-Type')
self.assertEqual(headers['X-Character-Encoding'], 'utf-8', '#7 response charset')
headers = self.get(url='/8')['headers']
self.assertEqual(headers['Content-Type'], 'text/html;charset=utf-8', '#8 Content-Type header')
self.assertEqual(headers['X-Content-Type'], 'text/html;charset=utf-8', '#8 response Content-Type')
self.assertEqual(headers['X-Character-Encoding'], 'utf-8', '#8 response charset')
def test_java_application_welcome_files(self):
self.load('welcome_files')
headers = self.get()['headers']
resp = self.get(url='/dir1')
self.assertEqual(resp['status'], 302, 'dir redirect expected')
resp = self.get(url='/dir1/')
self.assertEqual('This is index.txt.' in resp['body'], True, 'dir1 index body')
self.assertEqual(resp['headers']['X-TXT-Filter'], '1', 'TXT Filter header')
headers = self.get(url='/dir2/')['headers']
self.assertEqual(headers['X-Unit-JSP'], 'ok', 'JSP Ok header')
self.assertEqual(headers['X-JSP-Filter'], '1', 'JSP Filter header')
headers = self.get(url='/dir3/')['headers']
self.assertEqual(headers['X-App-Servlet'], '1', 'URL pattern overrides welcome file')
headers = self.get(url='/dir4/')['headers']
self.assertEqual('X-App-Servlet' in headers, False, 'Static welcome file served first')
headers = self.get(url='/dir5/')['headers']
self.assertEqual(headers['X-App-Servlet'], '1', 'Servlet for welcome file served when no static file found')
def test_java_application_request_listeners(self):
self.load('request_listeners')
headers = self.get(url='/test1')['headers']
self.assertEqual(headers['X-Request-Initialized'], '/test1',
'request initialized event')
self.assertEqual(headers['X-Request-Destroyed'], '',
'request destroyed event')
self.assertEqual(headers['X-Attr-Added'], '',
'attribute added event')
self.assertEqual(headers['X-Attr-Removed'], '',
'attribute removed event')
self.assertEqual(headers['X-Attr-Replaced'], '',
'attribute replaced event')
headers = self.get(url='/test2?var1=1')['headers']
self.assertEqual(headers['X-Request-Initialized'], '/test2',
'request initialized event')
self.assertEqual(headers['X-Request-Destroyed'], '/test1',
'request destroyed event')
self.assertEqual(headers['X-Attr-Added'], 'var=1;',
'attribute added event')
self.assertEqual(headers['X-Attr-Removed'], 'var=1;',
'attribute removed event')
self.assertEqual(headers['X-Attr-Replaced'], '',
'attribute replaced event')
headers = self.get(url='/test3?var1=1&var2=2')['headers']
self.assertEqual(headers['X-Request-Initialized'], '/test3',
'request initialized event')
self.assertEqual(headers['X-Request-Destroyed'], '/test2',
'request destroyed event')
self.assertEqual(headers['X-Attr-Added'], 'var=1;',
'attribute added event')
self.assertEqual(headers['X-Attr-Removed'], 'var=2;',
'attribute removed event')
self.assertEqual(headers['X-Attr-Replaced'], 'var=1;',
'attribute replaced event')
headers = self.get(url='/test4?var1=1&var2=2&var3=3')['headers']
self.assertEqual(headers['X-Request-Initialized'], '/test4',
'request initialized event')
self.assertEqual(headers['X-Request-Destroyed'], '/test3',
'request destroyed event')
self.assertEqual(headers['X-Attr-Added'], 'var=1;',
'attribute added event')
self.assertEqual(headers['X-Attr-Removed'], '',
'attribute removed event')
self.assertEqual(headers['X-Attr-Replaced'], 'var=1;var=2;',
'attribute replaced event')
def test_java_application_request_uri_forward(self):
self.load('forward')
resp = self.get(url='/fwd?uri=%2Fdata%2Ftest%3Furi%3Dnew_uri%26a%3D2%26b%3D3&a=1&c=4')
headers = resp['headers']
self.assertEqual(headers['X-REQUEST-Id'], 'fwd',
'initial request servlet mapping')
self.assertEqual(headers['X-Forward-To'], '/data/test?uri=new_uri&a=2&b=3',
'forwarding triggered')
self.assertEqual(headers['X-REQUEST-Param-uri'], '/data/test?uri=new_uri&a=2&b=3',
'original uri parameter')
self.assertEqual(headers['X-REQUEST-Param-a'], '1',
'original a parameter')
self.assertEqual(headers['X-REQUEST-Param-c'], '4',
'original c parameter')
self.assertEqual(headers['X-FORWARD-Id'], 'data',
'forward request servlet mapping')
self.assertEqual(headers['X-FORWARD-Request-URI'], '/data/test',
'forward request uri')
self.assertEqual(headers['X-FORWARD-Servlet-Path'], '/data',
'forward request servlet path')
self.assertEqual(headers['X-FORWARD-Path-Info'], '/test',
'forward request path info')
self.assertEqual(headers['X-FORWARD-Query-String'], 'uri=new_uri&a=2&b=3',
'forward request query string')
self.assertEqual(headers['X-FORWARD-Param-uri'], 'new_uri,/data/test?uri=new_uri&a=2&b=3',
'forward uri parameter')
self.assertEqual(headers['X-FORWARD-Param-a'], '2,1',
'forward a parameter')
self.assertEqual(headers['X-FORWARD-Param-b'], '3',
'forward b parameter')
self.assertEqual(headers['X-FORWARD-Param-c'], '4',
'forward c parameter')
self.assertEqual(headers['X-javax.servlet.forward.request_uri'], '/fwd',
'original request uri')
self.assertEqual(headers['X-javax.servlet.forward.context_path'], '',
'original request context path')
self.assertEqual(headers['X-javax.servlet.forward.servlet_path'], '/fwd',
'original request servlet path')
self.assertEqual(headers['X-javax.servlet.forward.path_info'], 'null',
'original request path info')
self.assertEqual(headers['X-javax.servlet.forward.query_string'], 'uri=%2Fdata%2Ftest%3Furi%3Dnew_uri%26a%3D2%26b%3D3&a=1&c=4',
'original request query')
self.assertEqual('Before forwarding' in resp['body'], False,
'discarded data added before forward() call')
self.assertEqual('X-After-Forwarding' in headers, False,
'cannot add headers after forward() call')
self.assertEqual('After forwarding' in resp['body'], False,
'cannot add data after forward() call')
def test_java_application_named_dispatcher_forward(self):
self.load('forward')
resp = self.get(url='/fwd?disp=name&uri=data')
headers = resp['headers']
self.assertEqual(headers['X-REQUEST-Id'], 'fwd',
'initial request servlet mapping')
self.assertEqual(headers['X-Forward-To'], 'data',
'forwarding triggered')
self.assertEqual(headers['X-FORWARD-Id'], 'data',
'forward request servlet mapping')
self.assertEqual(headers['X-FORWARD-Request-URI'], '/fwd',
'forward request uri')
self.assertEqual(headers['X-FORWARD-Servlet-Path'], '/fwd',
'forward request servlet path')
self.assertEqual(headers['X-FORWARD-Path-Info'], 'null',
'forward request path info')
self.assertEqual(headers['X-FORWARD-Query-String'], 'disp=name&uri=data',
'forward request query string')
self.assertEqual(headers['X-javax.servlet.forward.request_uri'], 'null',
'original request uri')
self.assertEqual(headers['X-javax.servlet.forward.context_path'], 'null',
'original request context path')
self.assertEqual(headers['X-javax.servlet.forward.servlet_path'], 'null',
'original request servlet path')
self.assertEqual(headers['X-javax.servlet.forward.path_info'], 'null',
'original request path info')
self.assertEqual(headers['X-javax.servlet.forward.query_string'], 'null',
'original request query')
self.assertEqual('Before forwarding' in resp['body'], False,
'discarded data added before forward() call')
self.assertEqual('X-After-Forwarding' in headers, False,
'cannot add headers after forward() call')
self.assertEqual('After forwarding' in resp['body'], False,
'cannot add data after forward() call')
def test_java_application_request_uri_include(self):
self.load('include')
resp = self.get(url='/inc?uri=/data/test')
headers = resp['headers']
body = resp['body']
self.assertEqual(headers['X-REQUEST-Id'], 'inc',
'initial request servlet mapping')
self.assertEqual(headers['X-Include'], '/data/test',
'including triggered')
self.assertEqual('X-INCLUDE-Id' in headers, False,
'unable to add headers in include request')
self.assertEqual('javax.servlet.include.request_uri: /data/test' in body,
True, 'include request uri')
# self.assertEqual('javax.servlet.include.context_path: ' in body,
# 'include request context path')
self.assertEqual('javax.servlet.include.servlet_path: /data' in body,
True, 'include request servlet path')
self.assertEqual('javax.servlet.include.path_info: /test' in body,
True, 'include request path info')
self.assertEqual('javax.servlet.include.query_string: null' in body,
True, 'include request query')
self.assertEqual('Before include' in body, True,
'preserve data added before include() call')
self.assertEqual(headers['X-After-Include'], 'you-should-see-this',
'add headers after include() call')
self.assertEqual('After include' in body, True,
'add data after include() call')
def test_java_application_named_dispatcher_include(self):
self.load('include')
resp = self.get(url='/inc?disp=name&uri=data')
headers = resp['headers']
body = resp['body']
self.assertEqual(headers['X-REQUEST-Id'], 'inc',
'initial request servlet mapping')
self.assertEqual(headers['X-Include'], 'data',
'including triggered')
self.assertEqual('X-INCLUDE-Id' in headers, False,
'unable to add headers in include request')
self.assertEqual('javax.servlet.include.request_uri: null' in body,
True, 'include request uri')
# self.assertEqual('javax.servlet.include.context_path: null' in body,
# 'include request context path')
self.assertEqual('javax.servlet.include.servlet_path: null' in body,
True, 'include request servlet path')
self.assertEqual('javax.servlet.include.path_info: null' in body,
True, 'include request path info')
self.assertEqual('javax.servlet.include.query_string: null' in body,
True, 'include request query')
self.assertEqual('Before include' in body, True,
'preserve data added before include() call')
self.assertEqual(headers['X-After-Include'], 'you-should-see-this',
'add headers after include() call')
self.assertEqual('After include' in body, True,
'add data after include() call')
def test_java_application_path_translation(self):
self.load('path_translation')
headers = self.get(url='/pt/test?path=/')['headers']
self.assertEqual(headers['X-Servlet-Path'], '/pt',
'matched servlet path')
self.assertEqual(headers['X-Path-Info'], '/test',
'the rest of the path')
self.assertEqual(headers['X-Path-Translated'],
headers['X-Real-Path'] + headers['X-Path-Info'],
'translated path is the app root + path info')
self.assertEqual(
headers['X-Resource-Paths'].endswith('/WEB-INF/, /index.html]'),
True, 'app root directory content')
self.assertEqual(headers['X-Resource-As-Stream'], 'null',
'no resource stream for root path')
headers = self.get(url='/test?path=/none')['headers']
self.assertEqual(headers['X-Servlet-Path'], '/test',
'matched whole path')
self.assertEqual(headers['X-Path-Info'], 'null',
'the rest of the path is null, whole path matched')
self.assertEqual(headers['X-Path-Translated'], 'null',
'translated path is null because path info is null')
self.assertEqual(headers['X-Real-Path'].endswith('/none'), True,
'read path is not null')
self.assertEqual(headers['X-Resource-Paths'], 'null',
'no resource found')
self.assertEqual(headers['X-Resource-As-Stream'], 'null',
'no resource stream')
def test_java_application_query_string(self):
self.load('query_string')
self.assertEqual(self.get(url='/?a=b')['headers']['X-Query-String'],
'a=b', 'query string')
def test_java_application_query_empty(self):
self.load('query_string')
self.assertEqual(self.get(url='/?')['headers']['X-Query-String'], '',
'query string empty')
def test_java_application_query_absent(self):
self.load('query_string')
self.assertEqual(self.get()['headers']['X-Query-String'], 'null',
'query string absent')
def test_java_application_empty(self):
self.load('empty')
self.assertEqual(self.get()['status'], 200, 'empty')
def test_java_application_keepalive_body(self):
self.load('mirror')
(resp, sock) = self.post(headers={
'Connection': 'keep-alive',
'Content-Type': 'text/html',
'Host': 'localhost'
}, start=True, body='0123456789' * 500)
self.assertEqual(resp['body'], '0123456789' * 500, 'keep-alive 1')
resp = self.post(headers={
'Connection': 'close',
'Content-Type': 'text/html',
'Host': 'localhost'
}, sock=sock, body='0123456789')
self.assertEqual(resp['body'], '0123456789', 'keep-alive 2')
def test_java_application_http_10(self):
self.load('empty')
self.assertEqual(self.get(http_10=True)['status'], 200, 'HTTP 1.0')
def test_java_application_no_method(self):
self.load('empty')
self.assertEqual(self.post()['status'], 405, 'no method')
def test_java_application_get_header(self):
self.load('get_header')
self.assertEqual(self.get(headers={
'X-Header': 'blah',
'Content-Type': 'text/html',
'Host': 'localhost'
})['headers']['X-Reply'], 'blah', 'get header')
def test_java_application_get_header_empty(self):
self.load('get_header')
self.assertNotIn('X-Reply', self.get()['headers'], 'get header empty')
def test_java_application_get_headers(self):
self.load('get_headers')
headers = self.get(headers={
'X-Header': ['blah', 'blah'],
'Content-Type': 'text/html',
'Host': 'localhost'
})['headers']
self.assertEqual(headers['X-Reply-0'], 'blah', 'get headers')
self.assertEqual(headers['X-Reply-1'], 'blah', 'get headers 2')
def test_java_application_get_headers_empty(self):
self.load('get_headers')
self.assertNotIn('X-Reply-0', self.get()['headers'],
'get headers empty')
def test_java_application_get_header_names(self):
self.load('get_header_names')
headers = self.get()['headers']
self.assertRegex(headers['X-Reply-0'], r'(?:Host|Connection)',
'get header names')
self.assertRegex(headers['X-Reply-1'], r'(?:Host|Connection)',
'get header names 2')
self.assertNotEqual(headers['X-Reply-0'], headers['X-Reply-1'],
'get header names not equal')
def test_java_application_get_header_names_empty(self):
self.load('get_header_names')
self.assertNotIn('X-Reply-0', self.get(headers={})['headers'],
'get header names empty')
def test_java_application_header_int(self):
self.load('header_int')
headers = self.get(headers={
'X-Header': '2',
'Content-Type': 'text/html',
'Host': 'localhost'
})['headers']
self.assertEqual(headers['X-Set-Int'], '1', 'set int header')
self.assertEqual(headers['X-Get-Int'], '2', 'get int header')
def test_java_application_header_date(self):
self.load('header_date')
date = 'Fri, 15 Mar 2019 14:45:34 GMT'
headers = self.get(headers={
'X-Header': date,
'Content-Type': 'text/html',
'Host': 'localhost'
})['headers']
self.assertEqual(headers['X-Set-Date'], 'Thu, 01 Jan 1970 00:00:01 GMT',
'set date header')
self.assertEqual(headers['X-Get-Date'], date, 'get date header')
if __name__ == '__main__':
TestUnitJavaApplication.main()

View File

@@ -600,6 +600,72 @@ class TestUnitApplicationNode(TestUnitApplicationProto):
}
})
class TestUnitApplicationJava(TestUnitApplicationProto):
def load(self, script, name='app'):
app_path = self.testdir + '/java'
web_inf_path = app_path + '/WEB-INF/'
classes_path = web_inf_path + 'classes/'
script_path = self.current_dir + '/java/' + script + '/'
if not os.path.isdir(app_path):
os.makedirs(app_path)
src = []
for f in os.listdir(script_path):
if f.endswith('.java'):
src.append(script_path + f)
continue
if f.startswith('.') or f == 'Makefile':
continue
if os.path.isdir(script_path + f):
if f == 'WEB-INF':
continue
shutil.copytree(script_path + f, app_path + '/' + f)
continue
if f == 'web.xml':
if not os.path.isdir(web_inf_path):
os.makedirs(web_inf_path)
shutil.copy2(script_path + f, web_inf_path)
else:
shutil.copy2(script_path + f, app_path)
if src:
if not os.path.isdir(classes_path):
os.makedirs(classes_path)
javac = ['javac', '-encoding', 'utf-8', '-d', classes_path,
'-classpath',
self.pardir + '/build/tomcat-servlet-api-9.0.13.jar']
javac.extend(src)
process = subprocess.Popen(javac)
process.communicate()
self.conf({
"listeners": {
"*:7080": {
"application": script
}
},
"applications": {
script: {
"unit_jars": self.pardir + '/build',
"type": "java",
"processes": { "spare": 0 },
"working_directory": script_path,
"webapp": app_path
}
}
})
class TestUnitApplicationPerl(TestUnitApplicationProto):
def load(self, script, name='psgi.pl'):
self.conf({