考虑这样一个使用场景,假如要查看所有进入weblogic上请求的(注意不是访问某个特定web app的)一些请求头是否设置,如果没有设置则返回以定制的页面.否则正常处理.
这么一个简单的需求在Tomcat下是很容易实现的,但是在weblogic下就比较奢侈了.
你可能想到weblogic中:
1)weblogic.security.net.ConnectionFilter
但是在ConnectionFilter中得到的信息太少了,根本不能查看请求头
2)提供IdentityAsserter Provider,实现weblogic.security.spi.IdentityAsserter
这个可以拿到看到你配置的特定的请求头了,但是还是不能查看完整请求,也不能写Response
weblogic9.1好像提供weblogic.security.spi.IdentityAsserterV2,这个类的assertIdentity()方法有个ContextHandler类,通过它可以访问到
HttpServletRequest,HttpServletResponse了,但是为了启用你的IdentityAsserter Provider,你必须在你要拦截的web应用中配置安全属性(web.xml)并且还得auth-method为CLIENT-CERT模式.
这种方式一般用来实现单点登陆.
那么,难道还有别的方法?
是的,下面介绍一种特别的方法(基于weblogic 7.1的,weblogic8.1也可以,但是要改动一点点)
weblogic domain的配置文件config.xml在<domain>元素下有一个<StartupClass>元素,用于设置一个容器启动类
<StartupClass ClassName="com.yovn.labs.wls.startup.Startup"
FailureIsFatal="true" LoadBeforeAppDeployments="true"
Name="MyStartup Class" Targets="myserver"/>
意义一目了然,就不多说了.
那么,在com.yovn.labs.wls.startup.Startup中干什么呢?
先通过weblogic.socket.JVMSocketManager.java来看看Weblogic是怎么管理Socket的
package weblogic.socket;
import weblogic.com.ProtocolHandlerDCOM;
import weblogic.iiop.ProtocolHandlerIIOP;
import weblogic.iiop.ProtocolHandlerIIOPS;
import weblogic.ldap.ProtocolHandlerLDAP;
import weblogic.rjvm.Protocol;
import weblogic.rjvm.t3.ProtocolHandlerT3;
import weblogic.rjvm.t3.ProtocolHandlerT3S;
import weblogic.servlet.internal.ProtocolHandlerHTTP;
import weblogic.servlet.internal.ProtocolHandlerHTTPS;
import weblogic.utils.AssertionError;
public final class JVMSocketManager
{
private static final boolean DEBUG = false;
private static final ProtocolHandler discHandlers[];
public static final int numDiscProtocols;
private static final ProtocolHandler defHandlers[];
public static final int numDefProtocols;
public JVMSocketManager()
{
}
static ProtocolHandler[] getDefaultProtocolHandlers()
{
return defHandlers;
}
static ProtocolHandler[] getDiscriminatingProtocolHandlers()
{
return discHandlers;
}
public static int[] makePortArray(int i, int j, int k, int l, int i1, int j1, int k1)
{
int ai[] = new int[7];
ai[0] = i;
ai[1] = j;
ai[2] = k;
ai[3] = l;
ai[4] = i1;
ai[5] = j1;
ai[6] = k1;
return ai;
}
static
{
try
{
discHandlers = (new ProtocolHandler[] {
ProtocolHandlerT3S.theHandler(), ProtocolHandlerT3.theHandler(), ProtocolHandlerIIOPS.theHandler(), ProtocolHandlerIIOP.theHandler(), ProtocolHandlerDCOM.theHandler(), ProtocolHandlerLDAP.theHandler()
});
numDiscProtocols = discHandlers.length;
defHandlers = (new ProtocolHandler[] {
ProtocolHandlerHTTPS.theHandler(), ProtocolHandlerHTTP.theHandler()
});
numDefProtocols = defHandlers.length;
}
catch(Throwable throwable)
{
throw new AssertionError("Protocol registration failed", throwable);
}
}
}
很显然,它的protocol handler是通过一个final 数组来管理,加入我在Startup类里修改defHandlers里的第二个元素,那么处理HTTP请求的protocol handler就可以被换掉了
来看我们的代码:
package com.yovn.labs.wls.startup;
import java.lang.reflect.Field;
import weblogic.socket.JVMSocketManager;
import weblogic.socket.ProtocolHandler;
import com.yovn.labs.wls.protocol.ProtocolHandlerHTTP;
/**
* @author yovn
*
*/
public class Startup {
/**
* @param args
* @throws NoSuchFieldException
* @throws SecurityException
*/
public static void main(String[] args) throws Exception {
Field f=JVMSocketManager.class.getDeclaredField("defHandlers");
f.setAccessible(true);
ProtocolHandler[] handlers=(ProtocolHandler[])f.get(null);
System.err.println("[Startup]===================================================:Mystart up class!");
System.err.println("[Startup]===================================================:default http handler is "+handlers[1]+"!");
handlers[1]=ProtocolHandlerHTTP.theHandler();
System.err.println("[Startup]===================================================:now, http handler is "+handlers[1]+"!");
}
}
好,现在HTTP Protocol Handler换成我们的 com.yovn.labs.wls.protocol.ProtocolHandlerHTTP类了
接下来就看我们的handler代码了
package com.yovn.labs.wls.protocol;
import java.io.IOException;
import java.net.ProtocolException;
import java.net.Socket;
//import weblogic.protocol.configuration.NetworkChannel;//在weblogic8.1中
import weblogic.rjvm.NetworkChannel;//在weblogic7.1中
import weblogic.socket.MuxableSocket;
import weblogic.socket.ProtocolHandler;
import weblogic.utils.io.Chunk;
public class ProtocolHandlerHTTP
implements ProtocolHandler
{
private static ProtocolHandler theOne = null;
protected static String PROTOCOL_NAME = "HTTP";
public ProtocolHandlerHTTP()
{
}
public static ProtocolHandler theHandler()
{
if(theOne == null)
synchronized(ProtocolHandlerHTTP.class)
{
if(theOne == null)
theOne = new ProtocolHandlerHTTP();
}
return theOne;
}
public int getHeaderLength()
{
return 0;
}
public String getProtocolName()
{
return PROTOCOL_NAME;
}
public boolean claimSocket(Chunk chunk, Socket socket)
throws IOException
{
return true;
}
public boolean canReadHeaders(byte abyte0[], int i)
{
return true;
}
public MuxableSocket createSocket(Chunk chunk, Socket socket, NetworkChannel networkchannel)
throws IOException
{
if(!networkchannel.isProtocolEnabled(2) && !networkchannel.isDefaultChannel())
{
throw new ProtocolException("HTTP is disabled");
} else
{
MuxableSocketHTTP muxablesockethttp = new MuxableSocketHTTP(chunk, socket, networkchannel);
return muxablesockethttp;
}
}
}
这段代码在要求创建MuxableSocket时创建了一个com.yovn.labs.wls.protocol.MuxableSocketHTTP,这个类里面就是我们做一些有意义的事情的地方了
来看代码:
package com.yovn.labs.wls.protocol;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.lang.reflect.Field;
import java.net.Socket;
import java.net.SocketException;
import weblogic.rjvm.NetworkChannel;
import weblogic.servlet.internal.RequestParser;
import weblogic.servlet.internal.ServletRequestImpl;
import weblogic.socket.MaxMessageSizeExceededException;
import weblogic.socket.MuxableSocket;
import weblogic.utils.io.Chunk;
/**
* @author yovn
*
*/
public class MuxableSocketHTTP implements MuxableSocket {
private final MuxableSocket delegate;//the internal implementation
private Field countF;
private Field bufF;
private Field sockF;
/* (non-Javadoc)
* @see weblogic.socket.MuxableSocket#dispatch()
*/
public void dispatch() {
try {
byte[] buf=(byte[])bufF.get(delegate);
int count=countF.getInt(delegate);
ServletRequestImpl servletrequestimpl = new ServletRequestImpl();
RequestParser requestparser = new RequestParser(servletrequestimpl,buf, count);
if(requestparser.parse()<0)
{
Socket sock=(Socket)sockF.get(delegate);
OutputStream out=sock.getOutputStream();
sendError(out,500,"Internal error");
out.close();
return;
}
String accessV=servletrequestimpl.getHeader("access");
if(accessV==null)
{
Socket sock=(Socket)sockF.get(delegate);
OutputStream out=sock.getOutputStream();
sendMessage(out,"You have not set 'access' header");
out.close();
return;
}
// System.out.println("+================================request first Line:"+servletrequestimpl.getFirstLine()+",request:"+servletrequestimpl.getRequestURI());
} catch (Exception e) {
e.printStackTrace();
}
delegate.dispatch();
}
void sendMessage(OutputStream out,String msg) throws IOException
{
String s="HTTP/1.1 "+200+" OK\r\n\r\n";
out.write(s.getBytes());
out.write(msg.getBytes());
out.flush();
}
void sendError(OutputStream out,int code,String msg) throws IOException
{
String s="HTTP/1.1 "+code+" "+msg+"\r\n\r\n";
out.write(s.getBytes());
out.flush();
}
public MuxableSocketHTTP(Chunk chunk1, Socket socket, NetworkChannel networkchannel)
throws IOException
{
//create our delegation first
delegate=new weblogic.servlet.internal.MuxableSocketHTTP(chunk1,socket,networkchannel);
//initiate private fields
try {
countF=weblogic.servlet.internal.MuxableSocketHTTP.class.getDeclaredField("count");
bufF=weblogic.servlet.internal.MuxableSocketHTTP.class.getDeclaredField("buf");
sockF=weblogic.servlet.internal.MuxableSocketHTTP.class.getDeclaredField("sock");
sockF.setAccessible(true);
countF.setAccessible(true);
bufF.setAccessible(true);
} catch (SecurityException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (NoSuchFieldException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
/* (non-Javadoc)
* @see weblogic.socket.MuxableSocket#endOfStream()
*/
public void endOfStream() {
delegate.endOfStream();
}
/* (non-Javadoc)
* @see weblogic.socket.MuxableSocket#getBuffer()
*/
public byte[] getBuffer() {
return delegate.getBuffer();
}
/* (non-Javadoc)
* @see weblogic.socket.MuxableSocket#getBufferOffset()
*/
public int getBufferOffset() {
return delegate.getBufferOffset();
}
/* (non-Javadoc)
* @see weblogic.socket.MuxableSocket#getCompleteMessageTimeoutMillis()
*/
public int getCompleteMessageTimeoutMillis() {
return delegate.getCompleteMessageTimeoutMillis();
}
/* (non-Javadoc)
* @see weblogic.socket.MuxableSocket#getIdleTimeoutMillis()
*/
public int getIdleTimeoutMillis() {
return delegate.getIdleTimeoutMillis();
}
/* (non-Javadoc)
* @see weblogic.socket.MuxableSocket#getMaxMessageSize()
*/
public int getMaxMessageSize() {
return delegate.getMaxMessageSize();
}
/* (non-Javadoc)
* @see weblogic.socket.MuxableSocket#getRawSocket()
*/
public Socket getRawSocket() {
return delegate.getRawSocket();
}
/* (non-Javadoc)
* @see weblogic.socket.MuxableSocket#getReRegisterMX()
*/
public MuxableSocket getReRegisterMX() {
return delegate.getReRegisterMX();
}
/* (non-Javadoc)
* @see weblogic.socket.MuxableSocket#getSocket()
*/
public Socket getSocket() {
return delegate.getSocket();
}
public void ensureForceClose() {
delegate.ensureForceClose();
}
public boolean isClosed() {
return delegate.isClosed();
}
/* (non-Javadoc)
* @see weblogic.socket.MuxableSocket#getSocketInputStream()
*/
public InputStream getSocketInputStream() {
return delegate.getSocketInputStream();
}
/* (non-Javadoc)
* @see weblogic.socket.MuxableSocket#hasException(java.lang.Throwable)
*/
public void hasException(Throwable arg0) {
delegate.hasException(arg0);
}
/* (non-Javadoc)
* @see weblogic.socket.MuxableSocket#incrementBufferOffset(int)
*/
public void incrementBufferOffset(int arg0)
throws MaxMessageSizeExceededException {
delegate.incrementBufferOffset(arg0);
}
/* (non-Javadoc)
* @see weblogic.socket.MuxableSocket#isMessageComplete()
*/
public boolean isMessageComplete() {
return delegate.isMessageComplete();
}
/* (non-Javadoc)
* @see weblogic.socket.MuxableSocket#setReRegisterMX(weblogic.socket.MuxableSocket)
*/
public void setReRegisterMX(MuxableSocket arg0) {
delegate.setReRegisterMX(arg0);
}
/* (non-Javadoc)
* @see weblogic.socket.MuxableSocket#setSoTimeout(int)
*/
public void setSoTimeout(int arg0) throws SocketException {
delegate.setSoTimeout(arg0);
}
}
主体在dispatch()方法里,我们先创建weblogic内部的MuxableSocketHttp作为我们真正的实现,然后利用RequestParser,ServletRequestImpl来解析
HTTP请求,解析后就可以查看详细的请求内容了,我们简单的检查一下一个特定的request header是否设置如果没有,则告知没有设置,否则正常处理.
好了,把上面的程序编译,打包,扔到你的weblogic domain下,修该domain的config.xml如本文开头所示.把你打好的包,加入你的weblogic类路径,启动weblogic.
Ok,现在你在浏览器里随便请求一个weblogic上的地址,你会看到如下页面:
You have not set 'access' header
我们再来写个测试程序,如下:
package com.yovn.labs.wls.test;
import java.io.ByteArrayOutputStream;
import java.io.InputStream;
import java.net.HttpURLConnection;
import java.net.URL;
/**
* @author yovn
*
*/
public class TestAccess {
/**
* @param args
*/
public static void main(String[] args)throws Exception {
URL url=new URL("http://localhost:7001/console");
HttpURLConnection conn=( HttpURLConnection)url.openConnection();
conn.addRequestProperty("access", "pass");
InputStream in=conn.getInputStream();
int len=0;
ByteArrayOutputStream bao=new ByteArrayOutputStream(1024*4);
byte[] bytes=new byte[1024];
while((len=in.read(bytes))>0)
{
bao.write(bytes,0,len);
}
in.close();
conn.disconnect();
System.out.println(bao.toString());
}
}
由于这个程序设置了'access'请求头,所打印出来内容就是正常请求该地址所产生的内容.
下载:
code and jar