This commit is contained in:
Mihai Pitu
2013-08-22 14:44:02 +03:00
committed by Felipe Zimmerle
parent 656f7c513c
commit e1cd024c26
17 changed files with 1306 additions and 59 deletions

90
java/Makefile.am Normal file
View File

@@ -0,0 +1,90 @@
pkglibdir = $(prefix)/lib
pkglib_LTLIBRARIES = libModSecurityJNI.la
libModSecurityJNI_la_SOURCES = ../apache2/mod_security2.c \
../apache2/apache2_config.c ../apache2/apache2_io.c ../apache2/apache2_util.c \
../apache2/re.c ../apache2/re_operators.c ../apache2/re_actions.c ../apache2/re_tfns.c \
../apache2/re_variables.c ../apache2/msc_logging.c ../apache2/msc_xml.c \
../apache2/msc_multipart.c ../apache2/modsecurity.c ../apache2/msc_parsers.c \
../apache2/msc_util.c ../apache2/msc_pcre.c ../apache2/persist_dbm.c ../apache2/msc_reqbody.c \
../apache2/msc_geo.c ../apache2/msc_gsb.c ../apache2/msc_unicode.c \
../apache2/acmp.c ../apache2/msc_lua.c ../apache2/msc_release.c \
../apache2/msc_crypt.c ../apache2/msc_tree.c ../apache2/libinjection/libinjection_sqli.c \
../standalone/api.c ../standalone/buckets.c \
../standalone/config.c ../standalone/filters.c \
../standalone/hooks.c ../standalone/regex.c ../standalone/server.c \
org_modsecurity_ModSecurity.c
libModSecurityJNI_la_CFLAGS = @APXS_CFLAGS@ @APR_CFLAGS@ @APU_CFLAGS@ \
@PCRE_CFLAGS@ @LIBXML2_CFLAGS@ @LUA_CFLAGS@ @MODSEC_EXTRA_CFLAGS@ @CURL_CFLAGS@
#libModSecurityJNI_la_CXXFLAGS = @APXS_CFLAGS@ @APR_CFLAGS@ @APU_CFLAGS@ \
# @PCRE_CFLAGS@ @LIBXML2_CFLAGS@ @LUA_CFLAGS@ @MODSEC_EXTRA_CFLAGS@ @CURL_CFLAGS@
libModSecurityJNI_la_CPPFLAGS = @APR_CPPFLAGS@ @PCRE_CPPFLAGS@ @LIBXML2_CPPFLAGS@ @JNI_CPPFLAGS@
libModSecurityJNI_la_LIBADD = @APR_LDADD@ @APU_LDADD@ @PCRE_LDADD@ @LIBXML2_LDADD@ @LUA_LDADD@
if AIX
libModSecurityJNI_la_LDFLAGS = -module -avoid-version \
@APR_LDFLAGS@ @APU_LDFLAGS@ @APXS_LDFLAGS@ \
@PCRE_LDFLAGS@ @LIBXML2_LDFLAGS@ @LUA_LDFLAGS@
endif
if HPUX
libModSecurityJNI_la_LDFLAGS = -module -avoid-version \
@APR_LDFLAGS@ @APU_LDFLAGS@ @APXS_LDFLAGS@ \
@PCRE_LDFLAGS@ @LIBXML2_LDFLAGS@ @LUA_LDFLAGS@
endif
if MACOSX
libModSecurityJNI_la_LDFLAGS = -module -avoid-version \
@APR_LDFLAGS@ @APU_LDFLAGS@ @APXS_LDFLAGS@ \
@PCRE_LDFLAGS@ @LIBXML2_LDFLAGS@ @LUA_LDFLAGS@
endif
if SOLARIS
libModSecurityJNI_la_LDFLAGS = -module -avoid-version \
@APR_LDFLAGS@ @APU_LDFLAGS@ @APXS_LDFLAGS@ \
@PCRE_LDFLAGS@ @LIBXML2_LDFLAGS@ @LUA_LDFLAGS@
endif
if LINUX
libModSecurityJNI_la_LDFLAGS = -no-undefined -module -avoid-version -R @PCRE_LD_PATH@ \
@APR_LDFLAGS@ @APU_LDFLAGS@ @APXS_LDFLAGS@ \
@PCRE_LDFLAGS@ @LIBXML2_LDFLAGS@ @LUA_LDFLAGS@
endif
if FREEBSD
libModSecurityJNI_la_LDFLAGS = -no-undefined -module -avoid-version \
@APR_LDFLAGS@ @APU_LDFLAGS@ @APXS_LDFLAGS@ \
@PCRE_LDFLAGS@ @LIBXML2_LDFLAGS@ @LUA_LDFLAGS@
endif
if OPENBSD
libModSecurityJNI_la_LDFLAGS = -no-undefined -module -avoid-version \
@APR_LDFLAGS@ @APU_LDFLAGS@ @APXS_LDFLAGS@ \
@PCRE_LDFLAGS@ @LIBXML2_LDFLAGS@ @LUA_LDFLAGS@
endif
if NETBSD
libModSecurityJNI_la_LDFLAGS = -no-undefined -module -avoid-version \
@APR_LDFLAGS@ @APU_LDFLAGS@ @APXS_LDFLAGS@ \
@PCRE_LDFLAGS@ @LIBXML2_LDFLAGS@ @LUA_LDFLAGS@
endif
if LINUX
install-exec-hook: $(pkglib_LTLIBRARIES)
@echo "Removing unused static libraries..."; \
for m in $(pkglib_LTLIBRARIES); do \
base=`echo $$m | sed 's/\..*//'`; \
rm -f $(DESTDIR)$(pkglibdir)/$$base.*a; \
install -D -m444 $(DESTDIR)$(pkglibdir)/$$base.so $(DESTDIR)$(APXS_MODULES)/$$base.so; \
done
else
install-exec-hook: $(pkglib_LTLIBRARIES)
@echo "Removing unused static libraries..."; \
for m in $(pkglib_LTLIBRARIES); do \
base=`echo $$m | sed 's/\..*//'`; \
rm -f $(DESTDIR)$(pkglibdir)/$$base.*a; \
cp -p $(DESTDIR)$(pkglibdir)/$$base.so $(DESTDIR)$(APXS_MODULES); \
done
endif

View File

@@ -164,7 +164,7 @@
<ClCompile Include="..\standalone\hooks.c" />
<ClCompile Include="..\standalone\regex.c" />
<ClCompile Include="..\standalone\server.c" />
<ClCompile Include="org_modsecurity_ModSecurity.cpp" />
<ClCompile Include="org_modsecurity_ModSecurity.c" />
</ItemGroup>
<ItemGroup>
<ClInclude Include="..\apache2\acmp.h" />

View File

@@ -117,7 +117,7 @@
<ClCompile Include="..\standalone\server.c">
<Filter>Standalone Sources</Filter>
</ClCompile>
<ClCompile Include="org_modsecurity_ModSecurity.cpp" />
<ClCompile Include="org_modsecurity_ModSecurity.c" />
</ItemGroup>
<ItemGroup>
<ClInclude Include="..\apache2\acmp.h">

Binary file not shown.

32
java/ModSecurityLoader/dist/README.TXT vendored Normal file
View File

@@ -0,0 +1,32 @@
========================
BUILD OUTPUT DESCRIPTION
========================
When you build an Java application project that has a main class, the IDE
automatically copies all of the JAR
files on the projects classpath to your projects dist/lib folder. The IDE
also adds each of the JAR files to the Class-Path element in the application
JAR files manifest file (MANIFEST.MF).
To run the project from the command line, go to the dist folder and
type the following:
java -jar "ModSecurityLoader.jar"
To distribute this project, zip up the dist folder (including the lib folder)
and distribute the ZIP file.
Notes:
* If two JAR files on the project classpath have the same name, only the first
JAR file is copied to the lib folder.
* Only JAR files are copied to the lib folder.
If the classpath contains other types of files or folders, these files (folders)
are not copied.
* If a library on the projects classpath also has a Class-Path element
specified in the manifest,the content of the Class-Path element has to be on
the projects runtime path.
* To set a main class in a standard Java project, right-click the project node
in the Projects window and choose Properties. Then click Run and enter the
class name in the Main Class field. Alternatively, you can manually type the
class name in the manifest Main-Class element.

View File

@@ -4,30 +4,37 @@ import java.io.File;
public class ModSecurityLoader {
private static final String MODSECURITYLIBSDIR_PATH = "c:\\work\\mod_security\\java\\libs\\"; //directory with ModSecurity native libraries
//private static final String MODSECURITYLIBSDIR_PATH = "c:\\work\\mod_security\\java\\libs\\"; //directory with ModSecurity native libraries
static {
File modSecDir = new File(MODSECURITYLIBSDIR_PATH);
File[] flibs = modSecDir.listFiles();
loadLib(flibs, "zlib1");
loadLib(flibs, "libxml2");
loadLib(flibs, "pcre");
loadLib(flibs, "libapr-1");
loadLib(flibs, "libapriconv-1");
loadLib(flibs, "libaprutil-1");
loadLib(flibs, "ModSecurityJNI");
System.out.println("ModSecurity loader static block executed.");
// File modSecDir = new File(MODSECURITYLIBSDIR_PATH);
// File[] flibs = modSecDir.listFiles();
// loadLib(flibs, "zlib1");
// loadLib(flibs, "libxml2");
// loadLib(flibs, "pcre");
// loadLib(flibs, "libapr-1");
// loadLib(flibs, "libapriconv-1");
// loadLib(flibs, "libaprutil-1");
// loadLib(flibs, "ModSecurityJNI");
//alternative load, this requires native libraries to be in java.library.path, you can set it
//by specifying server VM start-up option: -Djava.library.path=path/to/libs/
// System.loadLibrary("zlib1");
// System.loadLibrary("libxml2");
// System.loadLibrary("pcre");
// System.loadLibrary("libapr-1");
// System.loadLibrary("libapriconv-1");
// System.loadLibrary("libaprutil-1");
// System.loadLibrary("ModSecurityJNI");
try {
System.loadLibrary("zlib1"); //needed for libxml2 in Windows
} catch(UnsatisfiedLinkError ex) {
}
System.loadLibrary("libxml2");
System.loadLibrary("pcre");
System.loadLibrary("libapr-1");
try {
System.loadLibrary("libapriconv-1");
} catch(UnsatisfiedLinkError ex) { //needed for libaprutil-1 in Windows
}
System.loadLibrary("libaprutil-1");
System.loadLibrary("ModSecurityJNI");
System.out.println("ModSecurity native libraries loaded.");
}
private static void loadLib(File[] files, String lib) {

View File

@@ -7,10 +7,7 @@ import java.net.UnknownHostException;
import javax.servlet.FilterConfig;
import javax.servlet.ServletException;
/**
*
* @author Mihai Pitu
*/
public final class ModSecurity {
//From build/classes: >"c:\Program Files\Java\jdk1.7.0_05\bin\javah.exe" -classpath c:\work\apache-tomcat-7.0.39\lib\servlet-api.jar;. org.modsecurity.ModSecurity
@@ -23,14 +20,14 @@ public final class ModSecurity {
static {
//ModSecurityLoader calls System.load() for every native library needed by ModSecurity.
try {
Class.forName("org.modsecurity.loader.ModSecurityLoader");
System.out.println("ModSecurity libraries loaded.");
} catch (ClassNotFoundException ex) {
java.util.logging.Logger.getLogger(ModSecurity.class.getName()).log(java.util.logging.Level.SEVERE,
"ModSecurityLoader was not found, please make sure that you have \"ModSecurityLoader.jar\" in your server lib folder.", ex);
}
// try {
// Class.forName("org.modsecurity.loader.ModSecurityLoader");
// System.out.println("ModSecurity libraries loaded.");
// } catch (ClassNotFoundException ex) {
// java.util.logging.Logger.getLogger(ModSecurity.class.getName()).log(java.util.logging.Level.SEVERE,
// "ModSecurityLoader was not found, please make sure that you have \"ModSecurityLoader.jar\" in your server lib folder.", ex);
// }
//If the ModSecurityLoader is not used, native libraries can be loaded here, however this is bad practice since this will raise UnsatisfiedLinkError if
//ModSecurity is used in multiple webapps. This will also will raise problems when the web-app is redeployed and the server is running.
// System.load("c:\\work\\mod_security\\java\\libs\\zlib1.dll");
@@ -40,6 +37,19 @@ public final class ModSecurity {
// System.load("c:\\work\\mod_security\\java\\libs\\libapriconv-1.dll");
// System.load("c:\\work\\mod_security\\java\\libs\\libaprutil-1.dll");
// System.load("c:\\work\\mod_security\\java\\Debug\\ModSecurityJNI.dll");
try {
System.loadLibrary("zlib1"); //needed for libxml2 in Windows
} catch(UnsatisfiedLinkError ex) {
}
System.loadLibrary("libxml2");
System.loadLibrary("pcre");
System.loadLibrary("libapr-1");
try {
System.loadLibrary("libapriconv-1");
} catch(UnsatisfiedLinkError ex) { //needed for libaprutil-1 in Windows
}
System.loadLibrary("libaprutil-1");
System.loadLibrary("ModSecurityJNI");
}
public ModSecurity(FilterConfig fc, String confFile) throws ServletException {

View File

@@ -1,7 +1,6 @@
package org.modsecurity;
import java.io.IOException;
import java.net.URLDecoder;
import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.FilterConfig;

View File

@@ -491,7 +491,7 @@ public class MsHttpServletRequest extends HttpServletRequestWrapper {
*/
@Override
public Enumeration getParameterNames() {
Hashtable parameterNames = new Hashtable();
Hashtable<Object, Object> parameterNames = new Hashtable<Object, Object>();
for (int i = 0, n = parameters.size(); i < n; i++) {
Parameter p = (Parameter) parameters.get(i);
parameterNames.put(p.name, p.value);

View File

@@ -25,8 +25,8 @@ public class MsHttpServletResponse extends HttpServletResponseWrapper {
private static final int INTERCEPT_OBSERVE_ONLY = 2;
public static final String DEFAULT_CHARACTER_ENCODING = "ISO-8859-1";
private int interceptMode = INTERCEPT_ON;
private ArrayList headers = new ArrayList();
private ArrayList cookies = new ArrayList();
private ArrayList<Object> headers = new ArrayList<Object>();
private ArrayList<Object> cookies = new ArrayList<Object>();
private int status = -1;
private boolean committed = false;
private boolean suspended = false;
@@ -593,11 +593,11 @@ final class FastHttpDateFormat {
/**
* Formatter cache.
*/
protected static final HashMap formatCache = new HashMap();
protected static final HashMap<Object, Object> formatCache = new HashMap<Object, Object>();
/**
* Parser cache.
*/
protected static final HashMap parseCache = new HashMap();
protected static final HashMap<Object, Object> parseCache = new HashMap<Object, Object>();
// --------------------------------------------------------- Public Methods
/**
@@ -705,7 +705,7 @@ final class FastHttpDateFormat {
/**
* Update cache.
*/
private static void updateCache(HashMap cache, Object key,
private static void updateCache(HashMap<Object, Object> cache, Object key,
Object value) {
if (value == null) {
return;

View File

@@ -13,7 +13,7 @@
}
</style>
</head>
<body style="background: #333333;">
<div align="center" style="width:930px; margin:0 auto; box-shadow: 5px 5px 6px #000; background: #FFFFFF;">
<div style="width: 930px;">
@@ -39,17 +39,16 @@
</p>
<br />
<h3>Installation</h3>
<h2>Installation</h2>
<p>
First you need to choose whether to download and compile ModSecurity from the project's version control web-site:
<a href="https://github.com/SpiderLabs/ModSecurity">github.com/SpiderLabs/ModSecurity</a> or using pre-compiled binaries from
<a href="https://www.modsecurity.org/">modsecurity.org</a>. We will not discuss how to compile
the dependent native libraries needed since these steps are described in the README files from ModSecurity's repository.
<a href="https://www.modsecurity.org/">modsecurity.org</a>.
The native libraries (.so, .dll, etc.) needed for <b>ModSecurity for Java</b> are:
</p>
<ol>
<li>
zlib1
zlib1 (Windows only)
</li>
<li>
libxml2
@@ -61,25 +60,53 @@
libapr-1
</li>
<li>
libapriconv-1
libapriconv-1 (Windows only)
</li>
<li>
libaprutil-1
</li>
<li>
ModSecurityJNI
ModSecurityJNI (JNI wrapper for mod_security code)
</li>
</ol>
<p>
These native libraries are loaded by the <span class="code">ModSecurityLoader.jar</span>, which should be placed in your Java server library loader
(for example, in Tomcat 7: <span class="code">$CATALINA_HOME/lib</span>). You can build or modify the load directory of <span class="code">ModSecurityLoader</span> from
<span class="code">/mod_security/java/ModSecurityLoader/src/</span>. The libraries have to be copied in a directory (for example, <span class="code">c:\work\mod_security\java\libs\</span>),
which should be accessible to <span class="code">ModSecurityLoader.jar</span>.
These native libraries are used by the <a class="code" href="../src/java/org/modsecurity/ModSecurityFilter.java">ModSecurityFilter</a>.
</p>
<br />
<h4>Java Web Applications with ModSecurity Filter</h4>
<h3>Compile ModSecurity native library</h3>
<p>
Install required packages for compilation. For example, on Debian/Ubuntu like systems (Windows users have a Visual Studio solution):
</p>
<pre class="codecanvas">
sudo apt-get install g++ make automake autoconf libtool
</pre>
<p>
Install required dependent packages:
</p>
<pre class="codecanvas">
sudo apt-get install libxml2 libxml2-dev libxml2-utils libaprutil1 libaprutil1-dev apache2-prefork-dev
</pre>
<p>
Download mod_security source code from <a href="https://github.com/mihaipitu/ModSecurity">GitHub</a>, compile and install:
</p>
<pre class="codecanvas">
cd mod_security/
./autogen.sh
./configure --enable-java-module
make
</pre>
<p>
Copy compiled library in a convenient folder:
</p>
<pre class="codecanvas">
sudo cp ./java/.libs/libModSecurityJNI.so /usr/lib/
</pre>
<br />
<h3>Java Web Applications with ModSecurity Filter</h3>
<p>
ModSecurity for Java uses <a href="http://www.oracle.com/technetwork/java/filters-137243.html">Java Filters</a> in order to
intercept Http requests and responses. <b>ModsecurityTestApp</b> is an example of Java EE Web application using the ModSecurity
@@ -110,15 +137,41 @@
&lt;/filter&gt;
</code>
</pre>
<p>
The ModSecurity Filter makes use of the native libraries written in C/C++ using the JNI technology.
As stated earlier, the native libraries are loaded by the <span class="code">ModSecurityLoader.jar</span>
which should be loaded by the server at start-up. If you are unable to configure the server to load the
ModSecurity libraries at startup, you may load them in your web application although this is not
recommended because this will raise <span class="code">UnsatisfiedLinkError</span> if the ModSecurity
Filter is used in multiple applications within the same server.
</p>
There are two ways of loading native libraries by Java Web Applications:
<ol>
<li>
<h4>Loading native libraries directly in the ModSecurityFilter</h4>
<p>
Although this is the easier, this is not recommended because the JVM will raise
<span class="code">UnsatisfiedLinkError</span> if the ModSecurity Filter is used in
multiple applications within the same server.
The libraries are loaded in the <a class="code" href="../src/java/org/modsecurity/ModSecurity.java">ModSecurity</a> class using
<span class="code">System.loadLibrary()</span>. In this case the server has to be started with
the following VM options:
</p>
<pre class="codecanvas">
-Djava.library.path=/path/to/libraries/folder/
</pre>
<p>
You can specify multiple folders for the <span class="code">java.library.path</span> variable by using
: (colon) or ; (semi-colon), depending on your environment.
</p>
</li>
<li>
<h4>Loading native libraries when the Web Server starts</h4>
<p>
<a class="code" href="../../ModSecurityLoader/dist/ModSecurityLoader.jar">ModSecurityLoader.jar</a> should be placed
in the Java server library loader folder (for example, in Tomcat 7: <span class="code">$CATALINA_HOME/lib</span>).
You can build or modify the load directory of <span class="code">ModSecurityLoader</span> from
<span class="code">/mod_security/java/ModSecurityLoader/src/</span>.
</p>
</li>
</ol>
<br/>
<br/>
<br/>

View File

@@ -0,0 +1,797 @@
#undef inline
#define inline __inline
#include "org_modsecurity_ModSecurity.h"
#include "api.h"
#include <math.h>
#define MODSECURITY_JAVACLASS "org/modsecurity/ModSecurity"
#define SERVLETINPUTSTREAM_JAVACLASS "javax/servlet/ServletInputStream"
#define TOSTRING_MET "toString"
#define STRINGRETURN_SIG "()Ljava/lang/String;"
#define INPUTSTREAM_READ_MET "read"
#define INPUTSTREAM_READ_SIG "([BII)I"
#define MODSECURITY_LOG_MET "log"
#define MODSECURITY_LOG_SIG "(ILjava/lang/String;)V"
#define MODSECURITY__HTTPREQHEADERS_MET "getHttpRequestHeaders"
#define MODSECURITY__HTTPREQHEADERS_SIG "(Ljavax/servlet/http/HttpServletRequest;)[[Ljava/lang/String;"
#define MODSECURITY__HTTPRESHEADERS_MET "getHttpResponseHeaders"
#define MODSECURITY__HTTPRESHEADERS_SIG "(Ljavax/servlet/http/HttpServletResponse;)[[Ljava/lang/String;"
#define MODSECURITY__ISPV6_MET "isIPv6"
#define MODSECURITY__ISPV6_SIG "(Ljava/lang/String;)Z"
#define HTTPTRANSACTION_HTTPREQUEST_MET "getHttpRequest"
#define HTTPTRANSACTION_HTTPREQUEST_SIG "()Ljavax/servlet/http/HttpServletRequest;"
#define HTTPTRANSACTION_MSHTTPREQUEST_MET "getMsHttpRequest"
#define HTTPTRANSACTION_MSHTTPREQUEST_SIG "()Lorg/modsecurity/MsHttpServletRequest;"
#define HTTPTRANSACTION_MSHTTPRESPONSE_MET "getMsHttpResponse"
#define HTTPTRANSACTION_MSHTTPRESPONSE_SIG "()Lorg/modsecurity/MsHttpServletResponse;"
#define HTTPTRANSACTION_TRANSACTIONID_MET "getTransactionID"
#define SERVLETREQUEST_SERVERNAME_MET "getServerName"
#define SERVLETREQUEST_CHARENCODING_MET "getCharacterEncoding"
#define SERVLETREQUEST_CONTENTTYPE_MET "getContentType"
#define SERVLETREQUEST_SERVERPORT_MET "getServerPort"
#define SERVLETREQUEST_SERVERPORT_SIG "()I"
#define SERVLETREQUEST_REMOTEADDR_MET "getRemoteAddr"
#define SERVLETREQUEST_INPUTSTREAM_MET "getInputStream"
#define SERVLETREQUEST_INPUTSTREAM_SIG "()Ljavax/servlet/ServletInputStream;"
#define HTTPSERVLETREQUEST_PATHINFO_MET "getPathInfo"
#define HTTPSERVLETREQUEST_QUERYSTRING_MET "getQueryString"
#define HTTPSERVLETREQUEST_METHOD_MET "getMethod"
#define HTTPSERVLETREQUEST_PROTOCOL_MET "getProtocol"
#define HTTPSERVLETREQUEST_REQUESTURL_MET "getRequestURL"
#define HTTPSERVLETREQUEST_REQUESTURL_SIG "()Ljava/lang/StringBuffer;"
#define MSHTTPSERVLETREQUEST_READBODY_MET "readBody"
#define MSHTTPSERVLETREQUEST_READBODY_SIG "(I)V"
#define MSHTTPSERVLETREQUEST_SETBODY_MET "setBodyBytes"
#define MSHTTPSERVLETREQUEST_SETBODY_SIG "([B)V"
#define SERVLETRESPONSE_CONTENTTYPE_MET "getContentType"
#define SERVLETRESPONSE_CHARENCODING_MET "getCharacterEncoding"
#define MSSERVLETRESPONSE_OUTPUTSTREAM_MET "getByteArrayStream"
#define MSSERVLETRESPONSE_OUTPUTSTREAM_SIG "()Ljava/io/ByteArrayInputStream;"
//typedef struct {
JavaVM *jvm;
jobject modSecurityInstance;
directory_config *config;
//} JavaModSecurityContext;
jmethodID logMethod;
apr_table_t *requests;
apr_pool_t *requestsPool;
char *serverHostname;
#define JAVASERVLET_INSTREAM "MSReqBStr"
#define JAVASERVLET_OUTSTREAM "MSResBStr"
#define JAVASERVLET_TRANSACTION "MSTran"
void storeJavaServletContext(request_rec *r, const char *key, jobject obj)
{
apr_table_setn(r->notes, key, (const char *)obj);
}
void removeJavaServletContext(request_rec *r, const char *key)
{
apr_table_unset(r->notes, key);
}
jobject getJavaServletContext(request_rec *r, const char *key)
{
jobject obj = NULL;
request_rec *rx = NULL;
/* Look in the current request first. */
obj = (jobject)apr_table_get(r->notes, key);
if (obj != NULL)
return obj;
/* If this is a subrequest then look in the main request. */
if (r->main != NULL)
{
obj = (jobject)apr_table_get(r->main->notes, key);
if (obj != NULL)
{
return obj;
}
}
/* If the request was redirected then look in the previous requests. */
rx = r->prev;
while(rx != NULL)
{
obj = (jobject)apr_table_get(rx->notes, key);
if (obj != NULL)
{
return obj;
}
rx = rx->prev;
}
return NULL;
}
apr_sockaddr_t *CopySockAddr(jclass msClass, JNIEnv *env, apr_pool_t *pool, char *addrstr, jstring addrStrJstr)
{
jmethodID isIPv6Met = (*env)->GetStaticMethodID(env, msClass, MODSECURITY__ISPV6_MET, MODSECURITY__ISPV6_SIG);
jboolean isIPv6 = (*env)->CallStaticBooleanMethod(env, msClass, isIPv6Met, addrStrJstr);
apr_sockaddr_t *addr = (apr_sockaddr_t *)apr_palloc(pool, sizeof(apr_sockaddr_t));
int adrlen = 16, iplen = 4;
if(isIPv6)
{
adrlen = 46;
iplen = 16;
addr->family = AF_INET6;
}
else
addr->family = AF_INET;
addr->addr_str_len = adrlen;
addr->hostname = (char*) "unknown";
#ifdef WIN32
addr->ipaddr_len = sizeof(IN_ADDR);
#else
addr->ipaddr_len = sizeof(struct in_addr);
#endif
addr->ipaddr_ptr = &addr->sa.sin.sin_addr;
addr->pool = pool;
addr->port = 80;
#ifdef WIN32
memcpy(&addr->sa.sin.sin_addr.S_un.S_addr, addrstr, iplen);
#else
memcpy(&addr->sa.sin.sin_addr.s_addr, addrstr, iplen);
#endif
addr->sa.sin.sin_family = addr->family;
addr->sa.sin.sin_port = 80;
addr->salen = sizeof(addr->sa);
addr->servname = addr->hostname;
return addr;
}
inline char* fromJString(JNIEnv *env, jstring jStr, apr_pool_t *pool)
{
char *str;
if (jStr != NULL)
{
const char *jCStr = (*env)->GetStringUTFChars(env, jStr, NULL);
int len = strlen(jCStr);
str = (char*) apr_palloc(pool, len + 1);
memcpy(str, jCStr, len);
str[len] = '\0'; //null terminate
(*env)->ReleaseStringUTFChars(env, jStr, jCStr); //release java memory
}
else
str = (char*) "";
return str;
}
inline char* fromJStringMethod(JNIEnv *env, jmethodID method, jobject obj, apr_pool_t *pool)
{
jstring jStr = (jstring) (*env)->CallObjectMethod(env, obj, method);
return fromJString(env, jStr, pool);
}
void logSec(void *obj, int level, char *str)
{
JNIEnv *env;
jstring jStr;
if (!(*jvm)->AttachCurrentThread(jvm, (void **)&env, NULL)) //get the Enviroment from the JavaVM
{
jStr = (*env)->NewStringUTF(env, str);
(*env)->CallVoidMethod(env, modSecurityInstance, logMethod, level, jStr);
(*jvm)->DetachCurrentThread(jvm);
//in the context of a JVM thread, any leaked local references are automatically cleaned up
//(*env)->ReleaseStringUTFChars(jStr, str);
}
}
apr_status_t ReadBodyCallback(request_rec *r, char *buf, unsigned int length, unsigned int *readcnt, int *is_eos)
{
jobject inputStream = getJavaServletContext(r, JAVASERVLET_INSTREAM); //servlet request input stream
JNIEnv *env;
*readcnt = 0;
if(inputStream == NULL)
{
*is_eos = 1;
return APR_SUCCESS;
}
if (!(*jvm)->AttachCurrentThread(jvm, (void **)&env, NULL))
{
//read request body from the servlet input stream using 'read' method
jclass inputStreamClass = (*env)->FindClass(env, SERVLETINPUTSTREAM_JAVACLASS);
jmethodID read = (*env)->GetMethodID(env, inputStreamClass, INPUTSTREAM_READ_MET, INPUTSTREAM_READ_SIG);
jbyteArray byteArrayBuf = (*env)->NewByteArray(env, length);
jint count = (*env)->CallIntMethod(env, inputStream, read, byteArrayBuf, 0, length);
jbyte* bufferPtr = (*env)->GetByteArrayElements(env, byteArrayBuf, NULL);
if (count == -1 || count > length || (*env)->ExceptionCheck(env) == JNI_TRUE) //end of stream
{
*is_eos = 1;
}
else
{
*readcnt = count;
memcpy(buf, bufferPtr, *readcnt);
}
(*env)->ReleaseByteArrayElements(env, byteArrayBuf, bufferPtr, 0);
(*env)->DeleteLocalRef(env, byteArrayBuf);
(*jvm)->DetachCurrentThread(jvm);
}
return APR_SUCCESS;
}
apr_status_t WriteBodyCallback(request_rec *r, char *buf, unsigned int length)
{
jobject httpTransaction;
JNIEnv *env;
jclass httpTransactionClass;
jmethodID getHttpRequest;
jobject httpServletRequest;
jclass httpServletRequestClass;
jmethodID setBodyBytes;
jbyte *jbuf;
int i;
jbyteArray byteArrayBuf;
httpTransaction = getJavaServletContext(r, JAVASERVLET_TRANSACTION);
if(httpTransaction == NULL)
{
return APR_SUCCESS;
}
if (!(*jvm)->AttachCurrentThread(jvm, (void **)&env, NULL))
{
httpTransactionClass = (*env)->GetObjectClass(env, httpTransaction);
getHttpRequest = (*env)->GetMethodID(env, httpTransactionClass, HTTPTRANSACTION_MSHTTPREQUEST_MET, HTTPTRANSACTION_MSHTTPREQUEST_SIG);
httpServletRequest = (*env)->CallObjectMethod(env, httpTransaction, getHttpRequest);
httpServletRequestClass = (*env)->GetObjectClass(env, httpServletRequest);
setBodyBytes = (*env)->GetMethodID(env, httpServletRequestClass, MSHTTPSERVLETREQUEST_SETBODY_MET, MSHTTPSERVLETREQUEST_SETBODY_SIG);
jbuf = (jbyte*) apr_palloc(requestsPool, sizeof(jbyte) * length);
for (i = 0; i < length; i++)
jbuf[i] = buf[i];
byteArrayBuf = (*env)->NewByteArray(env, length);
(*env)->SetByteArrayRegion(env, byteArrayBuf, 0, length, jbuf);
//on setBodyBytes we copy buf bytes
(*env)->CallVoidMethod(env, httpServletRequest, setBodyBytes, byteArrayBuf);
//(*env)->ReleaseByteArrayElements(byteArrayBuf, jbuf, NULL);
(*jvm)->DetachCurrentThread(jvm);
}
return APR_SUCCESS;
}
apr_status_t ReadResponseCallback(request_rec *r, char *buf, unsigned int length, unsigned int *readcnt, int *is_eos)
{
jobject inputStream;
JNIEnv *env;
jclass inputStreamClass;
jmethodID read;
jbyteArray byteArrayBuf;
jint count;
jbyte* bufferPtr;
inputStream = getJavaServletContext(r, JAVASERVLET_OUTSTREAM);
*readcnt = 0;
if(inputStream == NULL)
{
*is_eos = 1;
return APR_SUCCESS;
}
if (!(*jvm)->AttachCurrentThread(jvm, (void **)&env, NULL))
{
inputStreamClass = (*env)->GetObjectClass(env, inputStream);
read = (*env)->GetMethodID(env, inputStreamClass, INPUTSTREAM_READ_MET, INPUTSTREAM_READ_SIG);
byteArrayBuf = (*env)->NewByteArray(env, length);
count = (*env)->CallIntMethod(env, inputStream, read, byteArrayBuf, 0, length);
bufferPtr = (*env)->GetByteArrayElements(env, byteArrayBuf, NULL);
if (count == -1 || count > length || (*env)->ExceptionCheck(env) == JNI_TRUE) //end of stream
{
*is_eos = 1;
}
else
{
*readcnt = count;
memcpy(buf, bufferPtr, *readcnt);
}
(*env)->ReleaseByteArrayElements(env, byteArrayBuf, bufferPtr, 0);
(*env)->DeleteLocalRef(env, byteArrayBuf);
(*jvm)->DetachCurrentThread(jvm);
}
return APR_SUCCESS;
}
apr_status_t WriteResponseCallback(request_rec *r, char *buf, unsigned int length)
{
JNIEnv *env;
jbyteArray byteArrayBuf;
jclass httpTransactionClass;
jmethodID getHttpResponse;
jobject httpServletResponse;
jbyte *jbuf;
int i;
jmethodID setBodyBytes;
jclass httpServletResponseClass;
jobject httpTransaction = getJavaServletContext(r, JAVASERVLET_TRANSACTION);
if(httpTransaction == NULL)
{
(*jvm)->DetachCurrentThread(jvm);
return APR_SUCCESS;
}
if (!(*jvm)->AttachCurrentThread(jvm, (void **)&env, NULL))
{
httpTransactionClass = (*env)->GetObjectClass(env, httpTransaction);
getHttpResponse = (*env)->GetMethodID(env, httpTransactionClass, HTTPTRANSACTION_MSHTTPRESPONSE_MET, HTTPTRANSACTION_MSHTTPRESPONSE_SIG);
httpServletResponse = (*env)->CallObjectMethod(env, httpTransaction, getHttpResponse);
httpServletResponseClass = (*env)->GetObjectClass(env, httpServletResponse);
setBodyBytes = (*env)->GetMethodID(env, httpServletResponseClass, MSHTTPSERVLETREQUEST_SETBODY_MET, MSHTTPSERVLETREQUEST_SETBODY_SIG);
jbuf = (jbyte*) apr_palloc(requestsPool, sizeof(jbyte) * length);
for (i = 0; i < length; i++)
jbuf[i] = buf[i];
byteArrayBuf = (*env)->NewByteArray(env, length);
(*env)->SetByteArrayRegion(env, byteArrayBuf, 0, length, jbuf);
//on setBodyBytes we copy buf bytes
(*env)->CallVoidMethod(env, httpServletResponse, setBodyBytes, byteArrayBuf);
//(*env)->ReleaseByteArrayElements(byteArrayBuf, jbuf, NULL);
(*jvm)->DetachCurrentThread(jvm);
}
return APR_SUCCESS;
}
JNIEXPORT jint JNICALL Java_org_modsecurity_ModSecurity_initialize(JNIEnv *env, jobject obj, jstring serverName)
{
(*env)->GetJavaVM(env, &jvm);
modSecurityInstance = (*env)->NewGlobalRef(env, obj); //Save the ModSecurity object for further use
logMethod = (*env)->GetMethodID(env, (*env)->GetObjectClass(env, obj), MODSECURITY_LOG_MET, MODSECURITY_LOG_SIG); //log method ID
modsecSetLogHook(NULL, logSec);
modsecSetReadBody(ReadBodyCallback);
modsecSetReadResponse(ReadResponseCallback);
modsecSetWriteBody(WriteBodyCallback);
modsecSetWriteResponse(WriteResponseCallback);
modsecInit();
modsecStartConfig();
config = modsecGetDefaultConfig();
modsecFinalizeConfig();
modsecInitProcess();
config = NULL;
//table for requests
apr_pool_create(&requestsPool, NULL);
requests = apr_table_make(requestsPool, 10);
serverHostname = fromJString(env, serverName, requestsPool);
return APR_SUCCESS;
}
JNIEXPORT jint JNICALL Java_org_modsecurity_ModSecurity_destroy(JNIEnv *env, jobject obj)
{
(*env)->DeleteGlobalRef(env, modSecurityInstance);
apr_pool_destroy(requestsPool);
modsecTerminate();
return APR_SUCCESS;
}
inline void setHeaders(JNIEnv *env, jclass httpServletRequestClass, jobject httpServletR, apr_table_t *reqHeaders, apr_pool_t *pool, const char *headersMet, const char *headersSig)
{
jmethodID getHttpHeaders;
jobjectArray headersTable;
jsize size;
int i;
//All headers are returned in a table by a static method from ModSecurity class
getHttpHeaders = (*env)->GetStaticMethodID(env, httpServletRequestClass, headersMet, headersSig);
headersTable = (jobjectArray) (*env)->CallStaticObjectMethod(env, httpServletRequestClass, getHttpHeaders, httpServletR);
size = (*env)->GetArrayLength(env, headersTable);
for (i = 0; i < size; i++)
{
const char *headerName;
const char *headerValue;
jobjectArray row = (jobjectArray) (*env)->GetObjectArrayElement(env, headersTable, i);
jstring headerNameJStr = (jstring) (*env)->GetObjectArrayElement(env, row, 0);
jstring headerValueJStr = (jstring) (*env)->GetObjectArrayElement(env, row, 1);
if (headerNameJStr != NULL && headerValueJStr != NULL)
{
headerName = fromJString(env, headerNameJStr, pool);
//apr_pool_cleanup_register(r->pool, headerName, memCleanup, apr_pool_cleanup_null);
headerValue = fromJString(env, headerValueJStr, pool);
//apr_pool_cleanup_register(r->pool, headerValue, memCleanup, apr_pool_cleanup_null);
apr_table_setn(reqHeaders, headerName, headerValue);
(*env)->DeleteLocalRef(env, headerNameJStr);
(*env)->DeleteLocalRef(env, headerValueJStr);
}
}
}
JNIEXPORT jint JNICALL Java_org_modsecurity_ModSecurity_onRequest(JNIEnv *env, jobject obj, jstring configPath, jobject httpTransaction, jboolean reloadConfig)
{
conn_rec *c;
request_rec *r;
const char *err;
jmethodID getHttpRequest;
jclass httpTransactionClass;
jobject httpServletRequest;
jobject servletRequest;
jclass httpServletRequestClass;
jclass servletRequestClass;
jclass modSecurityClass;
jmethodID readBody;
jmethodID getTransactionID;
jmethodID getInputStream;
const char *reqID;
jobject inputStream;
jmethodID getServerName;
jmethodID getServerPort;
int port;
char *port_str;
jmethodID getPathInfo;
jmethodID getQueryString;
jmethodID getCharacterEncoding;
jmethodID getContentType;
const char *lng;
jmethodID getMethod;
const char* method;
jmethodID getProtocol;
jmethodID getRequestURL;
jobject stringBuffer;
jmethodID toStringBuff;
char *url;
jmethodID getRemoteAddr;
jstring remoteAddrJStr;
char *remoteAddr;
int status;
int len;
if (config == NULL || reloadConfig)
{
const char *path;
config = modsecGetDefaultConfig();
path = fromJString(env, configPath, config->mp); //path to modsecurity.conf
err = modsecProcessConfig(config, path, NULL);
if(err != NULL)
{
logSec(NULL, 0, (char*)err);
return DONE;
}
}
c = modsecNewConnection();
modsecProcessConnection(c);
r = modsecNewRequest(c, config);
r->server->server_hostname = serverHostname;
httpTransactionClass = (*env)->GetObjectClass(env, httpTransaction);
getHttpRequest = (*env)->GetMethodID(env, httpTransactionClass, HTTPTRANSACTION_MSHTTPREQUEST_MET, HTTPTRANSACTION_MSHTTPREQUEST_SIG);
httpServletRequest = (*env)->CallObjectMethod(env, httpTransaction, getHttpRequest);
servletRequest = httpServletRequest; //superclass of HttpServletRequest
httpServletRequestClass = (*env)->GetObjectClass(env, httpServletRequest); //MsHttpServletRequest interface
servletRequestClass = (*env)->GetObjectClass(env, servletRequest); //ServletRequest interface
modSecurityClass = (*env)->GetObjectClass(env, obj); //ModSecurity class
//readBody method reads all bytes from the inputStream or a maximum of 'config->reqbody_limit' bytes
readBody = (*env)->GetMethodID(env, httpServletRequestClass, MSHTTPSERVLETREQUEST_READBODY_MET, MSHTTPSERVLETREQUEST_READBODY_SIG);
(*env)->CallVoidMethod(env, httpServletRequest, readBody, config->reqbody_limit);
if ((*env)->ExceptionCheck(env) == JNI_TRUE) //read body raised an Exception, return to JVM
{
modsecFinishRequest(r);
return DONE;
}
getTransactionID = (*env)->GetMethodID(env, httpTransactionClass, HTTPTRANSACTION_TRANSACTIONID_MET, STRINGRETURN_SIG);
reqID = fromJStringMethod(env, getTransactionID, httpTransaction, r->pool); //fromJString(env, requestID, r->pool); //unique ID of this request
apr_table_setn(requests, reqID, (const char*) r); //store this request for response processing
getInputStream = (*env)->GetMethodID(env, httpServletRequestClass, SERVLETREQUEST_INPUTSTREAM_MET, SERVLETREQUEST_INPUTSTREAM_SIG);
inputStream = (*env)->CallObjectMethod(env, httpServletRequest, getInputStream); //Request body input stream used in the read body callback
storeJavaServletContext(r, JAVASERVLET_INSTREAM, inputStream);
storeJavaServletContext(r, JAVASERVLET_TRANSACTION, httpTransaction);
getServerName = (*env)->GetMethodID(env, servletRequestClass, SERVLETREQUEST_SERVERNAME_MET, STRINGRETURN_SIG);
r->hostname = fromJStringMethod(env, getServerName, servletRequest, r->pool);
getServerPort = (*env)->GetMethodID(env, servletRequestClass, SERVLETREQUEST_SERVERPORT_MET, SERVLETREQUEST_SERVERPORT_SIG);
port = (*env)->CallIntMethod(env, servletRequest, getServerPort); //server port
port_str = apr_itoa(r->pool, port);
getPathInfo = (*env)->GetMethodID(env, httpServletRequestClass, HTTPSERVLETREQUEST_PATHINFO_MET, STRINGRETURN_SIG);
r->path_info = fromJStringMethod(env, getPathInfo, httpServletRequest, r->pool);
getQueryString = (*env)->GetMethodID(env, httpServletRequestClass, HTTPSERVLETREQUEST_QUERYSTRING_MET, STRINGRETURN_SIG);
r->args = fromJStringMethod(env, getQueryString, httpServletRequest, r->pool);
setHeaders(env, httpServletRequestClass, httpServletRequest, r->headers_in, r->pool, MODSECURITY__HTTPREQHEADERS_MET, MODSECURITY__HTTPREQHEADERS_SIG);
getCharacterEncoding = (*env)->GetMethodID(env, servletRequestClass, SERVLETREQUEST_CHARENCODING_MET, STRINGRETURN_SIG);
r->content_encoding = fromJStringMethod(env, getCharacterEncoding, servletRequest, r->pool);
getContentType = (*env)->GetMethodID(env, servletRequestClass, SERVLETREQUEST_CONTENTTYPE_MET, STRINGRETURN_SIG);
r->content_type = fromJStringMethod(env, getContentType, servletRequest, r->pool);
lng = apr_table_get(r->headers_in, "Content-Languages");
if(lng != NULL)
{
r->content_languages = apr_array_make(r->pool, 1, sizeof(const char *));
*(const char **)apr_array_push(r->content_languages) = lng;
}
getMethod = (*env)->GetMethodID(env, httpServletRequestClass, HTTPSERVLETREQUEST_METHOD_MET, STRINGRETURN_SIG);
method = fromJStringMethod(env, getMethod, httpServletRequest, r->pool);
//#define SETMETHOD(m) if(strcmp(method,#m) == 0){ r->method = method; r->method_number = M_##m; }
r->method = "INVALID";
r->method_number = M_INVALID;
//might be faster with elseif
if (strcmp(method, "OPTIONS") == 0) { r->method = method; r->method_number = M_OPTIONS; }
else if (strcmp(method, "GET") == 0) { r->method = method; r->method_number = M_GET; }
else if (strcmp(method, "POST") == 0) { r->method = method; r->method_number = M_POST; }
else if (strcmp(method, "PUT") == 0) { r->method = method; r->method_number = M_PUT; }
else if (strcmp(method, "DELETE") == 0) { r->method = method; r->method_number = M_DELETE; }
else if (strcmp(method, "TRACE") == 0) { r->method = method; r->method_number = M_TRACE; }
else if (strcmp(method, "CONNECT") == 0) { r->method = method; r->method_number = M_CONNECT; }
else if (strcmp(method, "MOVE") == 0) { r->method = method; r->method_number = M_MOVE; }
else if (strcmp(method, "COPY") == 0) { r->method = method; r->method_number = M_COPY; }
else if (strcmp(method, "PROPFIND") == 0) { r->method = method; r->method_number = M_PROPFIND; }
else if (strcmp(method, "PROPPATCH") == 0) { r->method = method; r->method_number = M_PROPPATCH; }
else if (strcmp(method, "MKCOL") == 0) { r->method = method; r->method_number = M_MKCOL; }
else if (strcmp(method, "LOCK") == 0) { r->method = method; r->method_number = M_LOCK; }
else if (strcmp(method, "UNLOCK") == 0) { r->method = method; r->method_number = M_UNLOCK; }
getProtocol = (*env)->GetMethodID(env, httpServletRequestClass, HTTPSERVLETREQUEST_PROTOCOL_MET, STRINGRETURN_SIG);
r->protocol = fromJStringMethod(env, getProtocol, httpServletRequest, r->pool);
r->request_time = apr_time_now();
r->parsed_uri.scheme = (char*) "http";
r->parsed_uri.path = r->path_info;
r->parsed_uri.hostname = (char *)r->hostname;
r->parsed_uri.is_initialized = 1;
r->parsed_uri.port = port;
r->parsed_uri.port_str = port_str;
r->parsed_uri.query = r->args;
r->parsed_uri.dns_looked_up = 0;
r->parsed_uri.dns_resolved = 0;
r->parsed_uri.password = NULL;
r->parsed_uri.user = NULL;
r->parsed_uri.fragment = NULL;
//the request Url is in a StringBuffer object
getRequestURL = (*env)->GetMethodID(env, httpServletRequestClass, HTTPSERVLETREQUEST_REQUESTURL_MET, HTTPSERVLETREQUEST_REQUESTURL_SIG);
stringBuffer = (*env)->CallObjectMethod(env, httpServletRequest, getRequestURL);
if (stringBuffer != NULL)
{
toStringBuff = (*env)->GetMethodID(env, (*env)->GetObjectClass(env, stringBuffer), TOSTRING_MET, STRINGRETURN_SIG);
url = fromJStringMethod(env, toStringBuff, stringBuffer, r->pool);
if (strcmp(r->args, "") != 0)
{
len = strlen(url) + 1 + strlen(r->args) + 1;
r->unparsed_uri = (char*)apr_palloc(r->pool, len); //unparsed uri with full query
strcpy(r->unparsed_uri, url);
strcat(r->unparsed_uri, "?");
strcat(r->unparsed_uri, r->args);
r->unparsed_uri[len] = 0;
}
else
{
r->unparsed_uri = url;
}
r->uri = r->unparsed_uri;
}
len = strlen(r->method) + 1 + strlen(r->uri) + 1 + strlen(r->protocol) + 1;
r->the_request = (char *)apr_palloc(r->pool, len);
strcpy(r->the_request, r->method);
strcat(r->the_request, " ");
strcat(r->the_request, r->uri);
strcat(r->the_request, " ");
strcat(r->the_request, r->protocol);
r->the_request[len] = 0;
apr_table_setn(r->subprocess_env, "UNIQUE_ID", reqID);
getRemoteAddr = (*env)->GetMethodID(env, servletRequestClass, SERVLETREQUEST_REMOTEADDR_MET, STRINGRETURN_SIG);
remoteAddrJStr = (jstring) (*env)->CallObjectMethod(env, servletRequest, getRemoteAddr);
remoteAddr = fromJString(env, remoteAddrJStr, r->pool);
//apr_pool_cleanup_register(r->pool, remoteAddr, memCleanup, apr_pool_cleanup_null);
#if AP_SERVER_MAJORVERSION_NUMBER > 1 && AP_SERVER_MINORVERSION_NUMBER < 3
c->remote_addr = CopySockAddr(modSecurityClass, env, r->pool, remoteAddr, remoteAddrJStr);
c->remote_ip = remoteAddr;
#else
c->client_addr = CopySockAddr(modSecurityClass, env, r->pool, remoteAddr, remoteAddrJStr);
c->client_ip = remoteAddr;
#endif
c->remote_host = NULL;
status = modsecProcessRequest(r);
removeJavaServletContext(r, JAVASERVLET_INSTREAM);
removeJavaServletContext(r, JAVASERVLET_TRANSACTION);
if (status != DECLINED) //Java modsecurityFilter blocks the request, onResponse will not be called, it's safe to finish the request
{
apr_table_unset(requests, reqID);
modsecFinishRequest(r);
}
return status;
}
JNIEXPORT jint JNICALL Java_org_modsecurity_ModSecurity_onResponse(JNIEnv *env, jobject obj, jobject httpTransaction)
{
jclass httpTransactionClass;
jmethodID getTransactionID;
jstring reqIDjStr;
const char *reqID;
request_rec *r;
jmethodID getHttpResponse;
jobject httpServletResponse;
jclass httpServletResponseClass;
jmethodID getOutputStream;
jobject responseStream;
jmethodID getContentType;
jmethodID getCharEncoding;
char *ct;
const char *lng;
int status;
httpTransactionClass = (*env)->GetObjectClass(env, httpTransaction);
getTransactionID = (*env)->GetMethodID(env, httpTransactionClass, HTTPTRANSACTION_TRANSACTIONID_MET, STRINGRETURN_SIG);
reqIDjStr = (jstring) (*env)->CallObjectMethod(env, httpTransaction, getTransactionID);
reqID = (*env)->GetStringUTFChars(env, reqIDjStr, NULL);
r = (request_rec*) apr_table_get(requests, reqID);
apr_table_unset(requests, reqID); //remove this request from the requests table
(*env)->ReleaseStringUTFChars(env, reqIDjStr, reqID);
if (r == NULL)
{
return DONE;
}
getHttpResponse = (*env)->GetMethodID(env, httpTransactionClass, HTTPTRANSACTION_MSHTTPRESPONSE_MET, HTTPTRANSACTION_MSHTTPRESPONSE_SIG);
httpServletResponse = (*env)->CallObjectMethod(env, httpTransaction, getHttpResponse);
httpServletResponseClass = (*env)->GetObjectClass(env, httpServletResponse); //MsHttpServletResponse class
//jclass modSecurityClass = (*env)->GetObjectClass(obj); //ModSecurity class
getOutputStream = (*env)->GetMethodID(env, httpServletResponseClass, MSSERVLETRESPONSE_OUTPUTSTREAM_MET, MSSERVLETRESPONSE_OUTPUTSTREAM_SIG);
responseStream = (*env)->CallObjectMethod(env, httpServletResponse, getOutputStream); //Response output stream used in the read response callback
if ((*env)->ExceptionCheck(env) == JNI_TRUE)
{
modsecFinishRequest(r);
return DONE;
}
storeJavaServletContext(r, JAVASERVLET_TRANSACTION, httpTransaction);
storeJavaServletContext(r, JAVASERVLET_OUTSTREAM, responseStream);
getContentType = (*env)->GetMethodID(env, httpServletResponseClass, SERVLETRESPONSE_CONTENTTYPE_MET, STRINGRETURN_SIG);
ct = fromJStringMethod(env, getContentType, httpServletResponse, r->pool);
if(strcmp(ct, "") == 0)
ct = (char*) "text/html";
r->content_type = ct;
getCharEncoding = (*env)->GetMethodID(env, httpServletResponseClass, SERVLETRESPONSE_CHARENCODING_MET, STRINGRETURN_SIG);
r->content_encoding = fromJStringMethod(env, getCharEncoding, httpServletResponse, r->pool);
setHeaders(env, httpServletResponseClass, httpServletResponse, r->headers_out, r->pool, MODSECURITY__HTTPRESHEADERS_MET, MODSECURITY__HTTPRESHEADERS_SIG);
lng = apr_table_get(r->headers_out, "Content-Languages");
if(lng != NULL)
{
r->content_languages = apr_array_make(r->pool, 1, sizeof(const char *));
*(const char **)apr_array_push(r->content_languages) = lng;
}
status = modsecProcessResponse(r);
removeJavaServletContext(r, JAVASERVLET_OUTSTREAM);
removeJavaServletContext(r, JAVASERVLET_TRANSACTION);
modsecFinishRequest(r);
return status;
}