Apr 25, 2007

Auto-encodes session IDs in URL

Blarg #22: A Filter that auto-encodes session IDs on relative page links.
Posted by jfalkner on March 27, 2006 at 10:43 PM | Comments (3)

This is an example Filter that auto-encodes all relative links on a website using the HttpServletResponse.encodeURL() method. It was originally encoded as an example during a Develop Mentor course I taught. It is a nice example of a servlet filter that buffers a response, locates links using a simple regular expression, and replaces links with encoded links.

The code. Remember each filter has three parts: the Filter, ServletResponseWrapper, and ServletOutputStream sub-class.

* EncodeSessionInURLFilter.java
* EncodeSessionInURLResponseWrapper.java
* EncodeSessionInURLResponseStream.java

EncodeSessionInURLFilter.java

This filter does nothing more than wraps the HttpServletResponse in order to buffer text sent out to a client.

package example;

import java.io.*;
import javax.servlet.*;
import javax.servlet.http.*;

public class EncodeSessionInURLFilter implements Filter {
ServletContext sc = null;

public void doFilter(ServletRequest req, ServletResponse res,
FilterChain chain) throws IOException, ServletException {
// check that it is a HTTP request
if (req instanceof HttpServletRequest) {
HttpServletRequest request = (HttpServletRequest) req;
HttpServletResponse response = (HttpServletResponse) res;

// nonce encode the normal output
EncodeSessionInURLResponseWrapper wrappedResponse = new EncodeSessionInURLResponseWrapper(
response, sc);

// make sure a session exists
HttpSession session = request.getSession(true);

chain.doFilter(req, wrappedResponse);
// finish the respone
wrappedResponse.finishResponse();
}
}

public void init(FilterConfig filterConfig) {
// reference the context
sc = filterConfig.getServletContext();
}

public void destroy() {
// noop
}
}


EncodeSessionInURLResponseWrapper.java

This wrapper sends back a custom ServletOutputStream object in order to buffer all text that is being sent to the client.

package example;

import java.io.*;
import java.util.*;
import javax.servlet.*;
import javax.servlet.http.*;

public class EncodeSessionInURLResponseWrapper extends HttpServletResponseWrapper {
protected HttpServletResponse origResponse = null;
protected ServletOutputStream stream = null;
protected PrintWriter writer = null;
ServletContext sc;

public EncodeSessionInURLResponseWrapper(HttpServletResponse response, ServletContext sc) {
super(response);
this.sc = sc;
origResponse = response;
}

public ServletOutputStream createOutputStream() throws IOException {
return (new EncodeSessionInURLResponseStream(origResponse, sc));
}

public void finishResponse() {
try {
if (writer != null) {
writer.close();
} else {
if (stream != null) {
stream.close();
}
}
} catch (IOException e) {}
}

public void flushBuffer() throws IOException {
stream.flush();
}

public ServletOutputStream getOutputStream() throws IOException {
if (writer != null) {
throw new IllegalStateException("getWriter() has already been called!");
}

if (stream == null)
stream = createOutputStream();
return (stream);
}

public PrintWriter getWriter() throws IOException {
if (writer != null) {
return (writer);
}

if (stream != null) {
throw new IllegalStateException("getOutputStream() has already been called!");
}

stream = createOutputStream();
// BUG FIX 2003-12-01 Reuse content's encoding, don't assume UTF-8
writer = new PrintWriter(new OutputStreamWriter(stream, origResponse.getCharacterEncoding()));
return (writer);
}

public void setContentLength(int length) {}
}


EncodeSessionInURLResponseStream.java

This response stream buffers all text that is send to the client and uses a regular expression to locate and replace links with encoded links.

package example;

import java.io.*;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import javax.servlet.*;
import javax.servlet.http.*;

/**
*
* @author Jayson Falkner - jayson@jspinsider.com
*/
public class EncodeSessionInURLResponseStream extends ServletOutputStream {
// abstraction of the output stream used for compression
protected OutputStream bufferedOutput = null;

// state keeping variable for if close() has been called
protected boolean closed = false;

// reference to original response
protected HttpServletResponse response = null;

// reference to the output stream to the client's browser
protected ServletOutputStream output = null;

// default size of the in-memory buffer
private int bufferSize = 50000;

ServletContext sc;

public EncodeSessionInURLResponseStream(HttpServletResponse response, ServletContext sc) throws IOException {
super();
closed = false;
this.sc = sc;
this.response = response;
this.output = response.getOutputStream();
bufferedOutput = new ByteArrayOutputStream();
}

public void close() throws IOException {
// make up a nonce
String nonce = Integer.toString((int)(Math.random()*Integer.MAX_VALUE));
// set the nonce in app scope
sc.setAttribute("nonce", nonce);

// get the content
ByteArrayOutputStream baos = (ByteArrayOutputStream) bufferedOutput;

// make a string out of the response
String pageText = new String(baos.toByteArray());

// use regex to find the links
Pattern p = Pattern.compile(" href=\"[^\"]*|action=\"[^\"]*");
Matcher m = p.matcher(pageText);

String newText = "";
int offset = 0;
while (m.find(offset)) {
// update the text
newText += pageText.substring(offset, m.start());
// update the offset
offset = m.end();
// get the matching string
String match = pageText.substring(m.start(), m.end());
// get the URL
String[] split = match.split("\"");
String url = split[1];
// encode the match
String encoded = response.encodeURL(url);

// add the match to the new text
newText += split[0]+"\""+encoded;
}
// add the final text
newText += pageText.substring(offset, pageText.length());



// set appropriate HTTP headers
// response.setContentLength(compressedBytes.length);
output.write(newText.getBytes());
output.flush();
output.close();
closed = true;

}

public void flush() throws IOException {
if (closed) {
throw new IOException("Cannot flush a closed output stream");
}
bufferedOutput.flush();
}

public void write(int b) throws IOException {
if (closed) {
throw new IOException("Cannot write to a closed output stream");
}
// write the byte to the temporary output
bufferedOutput.write((byte) b);
}

public void write(byte b[]) throws IOException {
write(b, 0, b.length);
}

public void write(byte b[], int off, int len) throws IOException {
System.out.println("writing...");
if (closed) {
throw new IOException("Cannot write to a closed output stream");
}
// write the content to the buffer
bufferedOutput.write(b, off, len);
}

public boolean closed() {
return (this.closed);
}

public void reset() {
//noop
}
}
in web.xml
<filter>
<filter-name>CookieSessionFilter</filter-name>
<filter-class> net.kokolink.zimbra.controller.EncodeSessionInURLFilter</filter-class>
</filter>
<filter-mapping>
<filter-name>CookieSessionFilter</filter-name>
<url-pattern>*.do</url-pattern>
</filter-mapping>

Apr 24, 2007

Handle duplicate form submission

Handle duplicate form submission
The problem of duplicate form submission arises when a user clicks the Submit button more than once before the response is sent back or when a client accesses a view by returning to a previously bookmarked page. This may result in inconsistent transactions and must be avoided. In our sample application, a similar problem will arise if the customer clicks the submit button more than once while submitting the purchase order.

In Struts this problem can be handled by using the saveToken() and isTokenValid() methods of Action class. saveToken() method creates a token (a unique string) and saves that in the user's current session, while isTokenValid() checks if the token stored in the user's current session is the same as that was passed as the request parameter.

To do this the JSP has to be loaded through an Action. Before loading the JSP call saveToken() to save the token in the user session. When the form is submitted, check the token against that in the session by calling isTokenValid(), as shown in the following code snippet:

Listing 3: Using saveToken() and isTokenValid()

public class PurchaseOrderAction extends DispatchAction

{

public ActionForward load(ActionMapping mapping,

ActionForm form,

HttpServletRequest request,

HttpServletResponse response) throws Exception

{

try

{ //save the token

saveToken(request)



// rest of the code for loading the form

}

catch(Exception ex){//exception}

}



public ActionForward submitOrder(ActionMapping mapping,

ActionForm form,

HttpServletRequest request,

HttpServletResponse response) throws Exception

{

try

{

// check the token. Proceed only if token is valid

if(isTokenValid(request,true)) {

//implement order submit functionality here

} else {

return mapping.findForward("failure");

}

}

catch(Exception ex){//exception}

}

}
Add this to jsp if you don't use <html:form> to enable store token on jsp
<input type="hidden" name="<%=Constants.TOKEN_KEY %>" value="<%=session.getAttribute(Globals.TRANSACTION_TOKEN_KEY) %>">

Apr 23, 2007

Làm thế nào để in giấy hai mặt

Để in giấy hai mặt không khó, tuy nhiên để tốn ít công sức nhất ta làm như sau:
- In mặt thứ nhất in Even pages với kiểu Reverse pages
- Sau khi kết thúc mặt 1, in mặt thứ hai với kiểu bình thường (không phải Reverse pages).
Như vậy là đã hoàn thành.

Apr 21, 2007

The best tool to scan the Spyware

Ad-Aware SE (free version) is the best choice to scan spyware in your computer.
You can download from here Download

Apr 11, 2007

Configure Java with Firefox

ln -s /usr/java/jdk1.5.0_06/jre/plugin/i386/ns7/libjavaplugin_oji.so /usr/local/firefox/plugins/

Apr 1, 2007

System Startup File

A single Linux system can provide several different services such as mail, Web, or FTP servers. Each service operates as a continually running daemon looking for requests for its particular services from remote users. We can turn services on or off by starting or shutting down their daemons. The process of starting or shutting down a service is handled by service scripts
1. System Startup File: /etc/rc.d and /etc/sysconfig
A series of startup commands are located in /etc/rc.d directory.
/etc/rc.d/rc.sysinit
holds the commands for initializing system, including the mounting and unmounting of file systems.
System Startup Files:
/etc/sysconfig: Directory that holds system configuration files and directories.
/etc/rc.d: Directory that holds system startup and shutdown files.
/etc/rc.d/rc.sysinit: Initialization file for system.
/etc/rc.d/rc.local: Initialization file for my own commands, can be free edit this file to add my own startup commands, this is the last startup file executed.
/etc/rc.d/modules: Loads kernel modules
/etc/rc.d/init.d:
Directory that holds network scripts to start up network connections.
/etc/rc.d/rc.num.d: Directories for different runlevels, where num is the runlevel. The directories hold links to scripts in the /etc/rd.d/init.d directory.
/etc/rc.d/init.d/halt: Operations performed each time you shut down the system, such as unmounting file systems, called rc.halt in other distributions.
/etc/rc.d/init.d/cups: Start up and shutdown the cups printer daemons.
/etc/rc.d/init.d/xinetd: Operations to start up or shutdown the xinetd daemon.
/etc/rc.d/init.d/network: Operations to start up or shutdown the network connections.
/etc/rc.d/init.d/httpd: Operations to start up or shutdown the Web server daemon, httpd.
To configure a service to start up automatically at boot, we can use te redhat-config-services tool available on the desktop or the chkconfig tool, which is run at a command line.