Index: src/java/org/apache/nutch/parse/ParseCallable.java
===================================================================
--- /dev/null	(revision )
+++ src/java/org/apache/nutch/parse/ParseCallable.java	(working copy)
@@ -0,0 +1,20 @@
+package org.apache.nutch.parse;
+
+import java.util.concurrent.Callable;
+
+import org.apache.nutch.protocol.Content;
+
+class ParseCallable implements Callable<ParseResult> {
+  private Parser p;
+  private Content content;
+  
+  public ParseCallable(Parser p, Content content) {
+    this.p = p;
+    this.content = content;
+  }
+
+  @Override
+  public ParseResult call() throws Exception {
+    return p.getParse(content);
+  }    
+}
\ No newline at end of file
Index: src/java/org/apache/nutch/parse/ParseUtil.java
===================================================================
--- src/java/org/apache/nutch/parse/ParseUtil.java	(revision )
+++ src/java/org/apache/nutch/parse/ParseUtil.java	(working copy)
@@ -17,6 +17,12 @@
 package org.apache.nutch.parse;
 
 // Commons Logging imports
+
+import java.util.concurrent.ExecutionException;
+import java.util.concurrent.FutureTask;
+import java.util.concurrent.TimeUnit;
+import java.util.concurrent.TimeoutException;
+
 import org.apache.commons.logging.Log;
 import org.apache.commons.logging.LogFactory;
 
@@ -42,6 +48,7 @@ public class ParseUtil {
   public static final Log LOG = LogFactory.getLog(ParseUtil.class);
   private ParserFactory parserFactory;
   private Configuration conf;
+  private int MAX_PARSE_TIME = 30; // 30 seconds should be enough for anybody...
   
   /**
    * 
@@ -81,7 +88,7 @@ public class ParseUtil {
       if (LOG.isDebugEnabled()) {
         LOG.debug("Parsing [" + content.getUrl() + "] with [" + parsers[i] + "]");
       }
-      parseResult = parsers[i].getParse(content);
+      parseResult = runParser(parsers[i], content);
       if (parseResult != null && !parseResult.isEmpty())
         return parseResult;
     }
@@ -126,7 +133,7 @@ public class ParseUtil {
       throw new ParseException(e.getMessage());
     }
     
-    ParseResult parseResult = p.getParse(content);
+    ParseResult parseResult = runParser(p, content);
     if (parseResult != null && !parseResult.isEmpty()) {
       return parseResult;
     } else {
@@ -136,6 +143,27 @@ public class ParseUtil {
       }  
       return null;
     }
-  }  
+  }
+
+  private ParseResult runParser(Parser p, Content content) {
+    ParseCallable pc = new ParseCallable(p, content);
+    FutureTask<ParseResult> task = new FutureTask<ParseResult>(pc);
+    ParseResult res = null;
+    Thread t = new Thread(task);
+    t.start();
+    try {
+      res = task.get(MAX_PARSE_TIME, TimeUnit.SECONDS);
+    } catch (TimeoutException e) {
+      LOG.warn("TIMEOUT parsing " + content.getUrl() + " with " + p);
+    } catch (Exception e) {
+      task.cancel(true);
+      res = null;
+      t.interrupt();
+    } finally {
+      t = null;
+      pc = null;
+    }
+    return res;
+  }
   
 }
