File Source: CommentServlet.java

     1  /*
     2   * Licensed to the Apache Software Foundation (ASF) under one or more
     3   *  contributor license agreements.  The ASF licenses this file to You
     4   * under the Apache License, Version 2.0 (the "License"); you may not
     5   * use this file except in compliance with the License.
     6   * You may obtain a copy of the License at
     7   *
     8   *     http://www.apache.org/licenses/LICENSE-2.0
     9   *
    10   * Unless required by applicable law or agreed to in writing, software
    11   * distributed under the License is distributed on an "AS IS" BASIS,
    12   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    13   * See the License for the specific language governing permissions and
    14   * limitations under the License.  For additional information regarding
    15   * copyright in this work, please see the NOTICE file in the top level
    16   * directory of this distribution.
    17   */
    18  
    19  package org.apache.roller.weblogger.ui.rendering.servlets;  
    20  
    21  import java.io.IOException;
    22  import java.sql.Timestamp;
    23  import java.util.Iterator;
    24  import javax.servlet.RequestDispatcher;
    25  import javax.servlet.ServletConfig;
    26  import javax.servlet.ServletException;
    27  import javax.servlet.http.HttpServlet;
    28  import javax.servlet.http.HttpServletRequest;
    29  import javax.servlet.http.HttpServletResponse;
    30  import org.apache.commons.logging.Log;
    31  import org.apache.commons.logging.LogFactory;
    32  import org.apache.roller.weblogger.WebloggerException;
    33  import org.apache.roller.weblogger.config.WebloggerConfig;
    34  import org.apache.roller.weblogger.config.WebloggerRuntimeConfig;
    35  import org.apache.roller.weblogger.business.search.IndexManager;
    36  import org.apache.roller.weblogger.business.WebloggerFactory;
    37  import org.apache.roller.weblogger.business.UserManager;
    38  import org.apache.roller.weblogger.business.WeblogManager;
    39  import org.apache.roller.weblogger.pojos.WeblogEntryComment;
    40  import org.apache.roller.weblogger.pojos.WeblogEntry;
    41  import org.apache.roller.weblogger.pojos.Weblog;
    42  import org.apache.roller.weblogger.ui.rendering.plugins.comments.CommentAuthenticator;
    43  import org.apache.roller.weblogger.ui.rendering.plugins.comments.CommentValidationManager;
    44  import org.apache.roller.weblogger.ui.rendering.plugins.comments.DefaultCommentAuthenticator;
    45  import org.apache.roller.weblogger.ui.rendering.util.WeblogCommentRequest;
    46  import org.apache.roller.weblogger.ui.rendering.util.WeblogEntryCommentForm;
    47  import org.apache.roller.weblogger.util.GenericThrottle;
    48  import org.apache.roller.weblogger.util.IPBanList;
    49  import org.apache.roller.weblogger.util.MailUtil;
    50  import org.apache.roller.weblogger.util.I18nMessages;
    51  import org.apache.roller.weblogger.util.RollerMessages;
    52  import org.apache.roller.weblogger.util.RollerMessages.RollerMessage;
    53  import org.apache.roller.weblogger.util.URLUtilities;
    54  import org.apache.roller.weblogger.util.Utilities;
    55  import org.apache.roller.weblogger.util.cache.CacheManager;
    56  
    57  
    58  /**
    59   * The CommentServlet handles all incoming weblog entry comment posts.
    60   *
    61   * We validate each incoming comment based on various comment settings and
    62   * if all checks are passed then the comment is saved.
    63   *
    64   * Incoming comments are tested against the MT Blacklist. If they are found
    65   * to be spam, then they are marked as spam and hidden from view.
    66   *
    67   * If email notification is turned on, each new comment will result in an
    68   * email sent to the blog owner and all who have commented on the same post.
    69   */
         /* 
    P/P   *  Method: void org.apache.roller.weblogger.ui.rendering.servlets.CommentServlet()
          * 
          *  Postconditions:
          *    this.authenticator == null
          *    this.commentThrottle == null
          *    this.commentValidationManager == null
          */
    70  public class CommentServlet extends HttpServlet {
    71      
             /* 
    P/P       *  Method: org.apache.roller.weblogger.ui.rendering.servlets.CommentServlet__static_init
              * 
              *  Postconditions:
              *    init'ed(log)
              */
    72      private static Log log = LogFactory.getLog(CommentServlet.class);
    73      
    74      private CommentAuthenticator     authenticator = null;
    75      private CommentValidationManager commentValidationManager = null;
    76      private GenericThrottle          commentThrottle = null;
    77      
    78      
    79      /**
    80       * Initialization.
    81       */
    82      public void init(ServletConfig servletConfig) throws ServletException {
    83          
                 /* 
    P/P           *  Method: void init(ServletConfig)
                  * 
                  *  Preconditions:
                  *    log != null
                  *    org/apache/roller/weblogger/ui/rendering/plugins/comments/CommentValidationManager.log != null
                  *    (soft) org/apache/roller/weblogger/util/cache/CacheManager.cacheFactory != null
                  *    (soft) org/apache/roller/weblogger/util/cache/CacheManager.cacheHandlers != null
                  *    (soft) org/apache/roller/weblogger/util/cache/CacheManager.caches != null
                  *    (soft) org/apache/roller/weblogger/util/cache/CacheManager.log != null
                  * 
                  *  Presumptions:
                  *    java.lang.Class:forName(...)@91 != null
                  *    java.lang.Integer:parseInt(...)@117 in -2_147_483..4_294_967
                  * 
                  *  Postconditions:
                  *    this.authenticator != null
                  *    this.commentThrottle == One-of{&new GenericThrottle(init#3), old this.commentThrottle}
                  *    this.commentValidationManager == &new CommentValidationManager(init#2)
                  *    new ArrayList(CommentValidationManager#1) num objects == 1
                  *    new CommentValidationManager(init#2) num objects == 1
                  *    init'ed(this.commentValidationManager.bundle)
                  *    this.commentValidationManager.validators == &new ArrayList(CommentValidationManager#1)
                  *    init'ed(new Date(LRUCacheImpl#1) num objects)
                  *    new DefaultCommentAuthenticator(init#1) num objects <= 1
                  *    init'ed(new ExpiringLRUCacheImpl(constructCache#1*) num objects)
                  *    ...
                  * 
                  *  Test Vectors:
                  *    org.apache.roller.weblogger.config.WebloggerConfig:getBooleanProperty(...)@106: {0}, {1}
                  */
    84          super.init(servletConfig);
    85          
    86          log.info("Initializing CommentServlet");
    87          
    88          // lookup the authenticator we are going to use and instantiate it
    89          try {
    90              String name = WebloggerConfig.getProperty("comment.authenticator.classname");
    91              Class clazz = Class.forName(name);
    92              this.authenticator = (CommentAuthenticator) clazz.newInstance();
    93          } catch(Exception e) {
    94              log.error(e);
    95              this.authenticator = new DefaultCommentAuthenticator();
    96          }
    97          
    98          // instantiate a comment validation manager for comment spam checking
    99          commentValidationManager = new CommentValidationManager();
   100          
   101          // instantiate a comment format manager for comment formatting
   102          String fmtrs = WebloggerConfig.getProperty("comment.formatter.classnames");
+  103          String[] formatters = Utilities.stringToStringArray(fmtrs, ",");
   104          
   105          // are we doing throttling?
   106          if(WebloggerConfig.getBooleanProperty("comment.throttle.enabled")) {
   107              
   108              int threshold = 25;
   109              try {
   110                  threshold = Integer.parseInt(WebloggerConfig.getProperty("comment.throttle.threshold"));
   111              } catch(Exception e) {
   112                  log.warn("bad input for config property comment.throttle.threshold", e);
   113              }
   114              
   115              int interval = 60000;
   116              try {
   117                  interval = Integer.parseInt(WebloggerConfig.getProperty("comment.throttle.interval"));
   118                  // convert from seconds to milliseconds
   119                  interval = interval * 1000;
   120              } catch(Exception e) {
   121                  log.warn("bad input for config property comment.throttle.interval", e);
   122              }
   123              
   124              int maxEntries = 250;
   125              try {
   126                  maxEntries = Integer.parseInt(WebloggerConfig.getProperty("comment.throttle.maxentries"));
   127              } catch(Exception e) {
   128                  log.warn("bad input for config property comment.throttle.maxentries", e);
   129              }
   130              
   131              commentThrottle = new GenericThrottle(threshold, interval, maxEntries);
   132              
   133              log.info("Comment Throttling ENABLED");
   134          } else {
   135              log.info("Comment Throttling DISABLED");
   136          }
   137      }
   138      
   139      
   140      /**
   141       * Handle incoming http GET requests.
   142       *
   143       * The CommentServlet does not support GET requests, it's a 404.
   144       */
   145      public void doGet(HttpServletRequest request, HttpServletResponse response)
   146              throws IOException, ServletException {
                 /* 
    P/P           *  Method: void doGet(HttpServletRequest, HttpServletResponse)
                  * 
                  *  Preconditions:
                  *    response != null
                  */
   147          response.sendError(HttpServletResponse.SC_NOT_FOUND);
   148      }
   149      
   150      
   151      /**
   152       * Service incoming POST requests.
   153       *
   154       * Here we handle incoming comment postings.
   155       */
   156      public void doPost(HttpServletRequest request, HttpServletResponse response)
   157              throws IOException, ServletException {
   158          
                 /* 
    P/P           *  Method: void doPost(HttpServletRequest, HttpServletResponse)
                  * 
                  *  Preconditions:
                  *    log != null
                  *    request != null
                  *    init'ed(this.commentThrottle)
                  *    (soft) init'ed(org/apache/roller/weblogger/util/IPBanList.instance.bannedIps)
                  *    (soft) init'ed(org/apache/roller/weblogger/util/IPBanList.instance.bannedIpsFile.myLastModified)
                  *    (soft) init'ed(this.commentThrottle.clientHistoryCache.hits)
                  *    (soft) init'ed(this.commentThrottle.clientHistoryCache.misses)
                  *    (soft) init'ed(this.commentThrottle.clientHistoryCache.puts)
                  *    (soft) org/apache/roller/weblogger/ui/rendering/plugins/comments/CommentValidationManager.log != null
                  *    (soft) org/apache/roller/weblogger/util/GenericThrottle.log != null
                  *    ...
                  * 
                  *  Presumptions:
                  *    java.util.Iterator:next(...)@305 != null
                  *    javax.servlet.http.HttpServletRequest:getRequestDispatcher(...)@273 != null
                  *    javax.servlet.http.HttpServletRequest:getRequestDispatcher(...)@371 != null
                  *    messageUtils.bundle != null
                  *    org.apache.roller.weblogger.business.UserManager:getWebsiteByHandle(...)@196 != null
                  *    ...
                  * 
                  *  Postconditions:
                  *    org/apache/roller/weblogger/util/IPBanList.instance.bannedIps == One-of{old org/apache/roller/weblogger/util/IPBanList.instance.bannedIps, &new HashSet(loadBannedIps#1)}
                  *    init'ed(org/apache/roller/weblogger/util/IPBanList.instance.bannedIps)
                  *    (soft) init'ed(org/apache/roller/weblogger/util/IPBanList.instance.bannedIpsFile.myLastModified)
                  *    this.commentThrottle.clientHistoryCache.hits == One-of{old this.commentThrottle.clientHistoryCache.hits, old this.commentThrottle.clientHistoryCache.hits + 1, One-of{old this.commentThrottle.clientHistoryCache.hits, old this.commentThrottle.clientHistoryCache.hits + 1} - 1}
                  *    (soft) init'ed(this.commentThrottle.clientHistoryCache.hits)
                  *    this.commentThrottle.clientHistoryCache.misses == One-of{old this.commentThrottle.clientHistoryCache.misses, old this.commentThrottle.clientHistoryCache.misses + 1}
                  *    (soft) init'ed(this.commentThrottle.clientHistoryCache.misses)
                  *    this.commentThrottle.clientHistoryCache.puts == One-of{old this.commentThrottle.clientHistoryCache.puts, old this.commentThrottle.clientHistoryCache.puts + 1}
                  *    (soft) init'ed(this.commentThrottle.clientHistoryCache.puts)
                  *    this.commentThrottle.clientHistoryCache.removes == One-of{old this.commentThrottle.clientHistoryCache.removes, old this.commentThrottle.clientHistoryCache.removes + 1, One-of{old this.commentThrottle.clientHistoryCache.removes, old this.commentThrottle.clientHistoryCache.removes + 1} + 1}
                  *    ...
                  * 
                  *  Test Vectors:
                  *    this.commentThrottle: Addr_Set{null}, Inverse{null}
                  *    errorKey.mArgs@305: Addr_Set{null}, Inverse{null}
                  *    java.lang.String:equals(...)@171: {0}, {1}
                  *    java.lang.String:equals(...)@323: {0}, {1}
                  *    java.util.Iterator:hasNext(...)@304: {0}, {1}
                  *    java.util.List:size(...)@70: {-231..0}, {1..232-1}
                  *    javax.servlet.http.HttpServletRequest:getParameter(...)@169: Addr_Set{null}, Inverse{null}
                  *    org.apache.roller.weblogger.config.WebloggerRuntimeConfig:getBooleanProperty(...)@241: {0}, {1}
                  *    org.apache.roller.weblogger.config.WebloggerRuntimeConfig:getBooleanProperty(...)@323: {1}, {0}
                  *    org.apache.roller.weblogger.pojos.Weblog:getCommentModerationRequired(...)@283: {0}, {1}
                  *    ...
                  */
   159          String error = null;
   160          String dispatch_url = null;
   161          
   162          Weblog weblog = null;
   163          WeblogEntry entry = null;
   164          
   165          String message = null;
   166          RollerMessages messages = new RollerMessages();
   167          
   168          // are we doing a preview?  or a post?
   169          String method = request.getParameter("method");
   170          final boolean preview;
   171          if (method != null && method.equals("preview")) {
   172              preview = true;
   173              messages.addMessage("commentServlet.previewCommentOnly");
   174              log.debug("Handling comment preview post");
   175          } else {
   176              preview = false;
   177              log.debug("Handling regular comment post");
   178          }
   179          
   180          // throttling protection against spammers
   181          if(commentThrottle != null &&
   182                  commentThrottle.processHit(request.getRemoteAddr())) {
   183              
   184              log.debug("ABUSIVE "+request.getRemoteAddr());
+  185              IPBanList.getInstance().addBannedIp(request.getRemoteAddr());
   186              response.sendError(HttpServletResponse.SC_NOT_FOUND);
   187              return;
   188          }
   189          
   190          WeblogCommentRequest commentRequest = null;
   191          try {
   192              commentRequest = new WeblogCommentRequest(request);
   193              
   194              // lookup weblog specified by comment request
   195              UserManager uMgr = WebloggerFactory.getWeblogger().getUserManager();
   196              weblog = uMgr.getWebsiteByHandle(commentRequest.getWeblogHandle());
   197              
   198              if(weblog == null) {
   199                  throw new WebloggerException("unable to lookup weblog: "+
   200                          commentRequest.getWeblogHandle());
   201              }
   202              
   203              // lookup entry specified by comment request
   204              entry = commentRequest.getWeblogEntry();
   205              if(entry == null) {
   206                  throw new WebloggerException("unable to lookup entry: "+
   207                          commentRequest.getWeblogAnchor());
   208              }
   209              
   210              // we know what the weblog entry is, so setup our urls
   211              dispatch_url = "/roller-ui/rendering/page/"+weblog.getHandle();
   212              if(commentRequest.getLocale() != null) {
   213                  dispatch_url += "/"+commentRequest.getLocale();
   214              }
   215              dispatch_url += "/entry/"+URLUtilities.encode(commentRequest.getWeblogAnchor());
   216              
   217          } catch (Exception e) {
   218              // some kind of error parsing the request or looking up weblog
   219              log.debug("error creating page request", e);
   220              response.sendError(HttpServletResponse.SC_NOT_FOUND);
   221              return;
   222          }
   223          
   224          
   225          log.debug("Doing comment posting for entry = "+entry.getPermalink());
   226          
   227          // collect input from request params and construct new comment object
   228          // fields: name, email, url, content, notify
   229          // TODO: data validation on collected comment data
   230          WeblogEntryComment comment = new WeblogEntryComment();
   231          comment.setName(commentRequest.getName());
   232          comment.setEmail(commentRequest.getEmail());
   233          comment.setUrl(commentRequest.getUrl());
   234          comment.setContent(commentRequest.getContent());
   235          comment.setNotify(new Boolean(commentRequest.isNotify()));
   236          comment.setWeblogEntry(entry);
   237          comment.setRemoteHost(request.getRemoteHost());
   238          comment.setPostTime(new Timestamp(System.currentTimeMillis()));
   239          
   240          // set comment content-type depending on if html is allowed
   241          if(WebloggerRuntimeConfig.getBooleanProperty("users.comments.htmlenabled")) {
   242              comment.setContentType("text/html");
   243          } else {
   244              comment.setContentType("text/plain");
   245          }
   246          
   247          // set whatever comment plugins are configured
   248          comment.setPlugins(WebloggerRuntimeConfig.getProperty("users.comments.plugins"));
   249          
   250          WeblogEntryCommentForm cf = new WeblogEntryCommentForm();
   251          cf.setData(comment);
   252          if (preview) {
   253              cf.setPreview(comment);
   254          }
   255          
   256          I18nMessages messageUtils = I18nMessages.getMessages(commentRequest.getLocaleInstance());
   257          
   258          // check if comments are allowed for this entry
   259          // this checks site-wide settings, weblog settings, and entry settings
   260          if(!entry.getCommentsStillAllowed() || !entry.isPublished()) {
   261              error = messageUtils.getString("comments.disabled");
   262              
   263          // if this is a real comment post then authenticate request
   264          } else if(!preview && !this.authenticator.authenticate(request)) {
   265              error = messageUtils.getString("error.commentAuthFailed");
   266              log.debug("Comment failed authentication");
   267          }
   268          
   269          // bail now if we have already found an error
   270          if(error != null) {
   271              cf.setError(error);
   272              request.setAttribute("commentForm", cf);
   273              RequestDispatcher dispatcher = request.getRequestDispatcher(dispatch_url);
   274              dispatcher.forward(request, response);
   275              return;
   276          }
   277          
   278          int validationScore = commentValidationManager.validateComment(comment, messages);
   279          log.debug("Comment Validation score: " + validationScore);
   280          
   281          if (!preview) {
   282              
   283              if (validationScore == 100 && weblog.getCommentModerationRequired()) {
   284                  // Valid comments go into moderation if required
   285                  comment.setStatus(WeblogEntryComment.PENDING);
   286                  message = messageUtils.getString("commentServlet.submittedToModerator");
   287              } else if (validationScore == 100) {
   288                  // else they're approved
   289                  comment.setStatus(WeblogEntryComment.APPROVED);
   290                  message = messageUtils.getString("commentServlet.commentAccepted");
   291              } else {
   292                  // Invalid comments are marked as spam
   293                  log.debug("Comment marked as spam");
   294                  comment.setStatus(WeblogEntryComment.SPAM);
   295                  error = messageUtils.getString("commentServlet.commentMarkedAsSpam");
   296                  
   297                  // add specific error messages if they exist
   298                  if(messages.getErrorCount() > 0) {
   299                      Iterator errors = messages.getErrors();
   300                      RollerMessage errorKey = null;
   301                      
   302                      StringBuffer buf = new StringBuffer();
   303                      buf.append("<ul>");
   304                      while(errors.hasNext()) {
   305                          errorKey = (RollerMessage)errors.next();
   306                          
   307                          buf.append("<li>");
   308                          if(errorKey.getArgs() != null) {
   309                              buf.append(messageUtils.getString(errorKey.getKey(), errorKey.getArgs()));
   310                          } else {
   311                              buf.append(messageUtils.getString(errorKey.getKey()));
   312                          }
   313                          buf.append("</li>");
   314                      }
   315                      buf.append("</ul>");
   316                      
   317                      error += buf.toString();
   318                  }
   319                  
   320              }
   321              
   322              try {               
   323                  if(!WeblogEntryComment.SPAM.equals(comment.getStatus()) ||
   324                          !WebloggerRuntimeConfig.getBooleanProperty("comments.ignoreSpam.enabled")) {
   325                      
   326                      WeblogManager mgr = WebloggerFactory.getWeblogger().getWeblogManager();
   327                      mgr.saveComment(comment);
   328                      WebloggerFactory.getWeblogger().flush();
   329                      
   330                      // Send email notifications only to subscribers if comment is 100% valid
   331                      boolean notifySubscribers = (validationScore == 100);
   332                      MailUtil.sendEmailNotification(comment, messages, messageUtils, notifySubscribers);
   333                      
   334                      // only re-index/invalidate the cache if comment isn't moderated
   335                      if(!weblog.getCommentModerationRequired()) {
   336                          IndexManager manager = WebloggerFactory.getWeblogger().getIndexManager();
   337                          
   338                          // remove entry before (re)adding it, or in case it isn't Published
   339                          manager.removeEntryIndexOperation(entry);
   340                          
   341                          // if published, index the entry
   342                          if (entry.isPublished()) {
   343                              manager.addEntryIndexOperation(entry);
   344                          }
   345                          
   346                          // Clear all caches associated with comment
   347                          CacheManager.invalidate(comment);
   348                      }
   349                      
   350                      // comment was successful, clear the comment form
   351                      cf = new WeblogEntryCommentForm();
   352                  }
   353                  
   354              } catch (WebloggerException re) {
   355                  log.error("Error saving comment", re);
   356                  error = re.getMessage();
   357              }
   358          }
   359          
   360          
   361          // the work has been done, now send the user back to the entry page
   362          if (error != null) {
   363              cf.setError(error);
   364          }
   365          if (message != null) {
   366              cf.setMessage(message);
   367          }
   368          request.setAttribute("commentForm", cf);
   369          
   370          log.debug("comment processed, forwarding to "+dispatch_url);
   371          RequestDispatcher dispatcher =
   372                  request.getRequestDispatcher(dispatch_url);
   373          dispatcher.forward(request, response);
   374      }
   375      
   376  }








SofCheck Inspector Build Version : 2.18479
CommentServlet.java 2009-Jan-02 14:25:20
CommentServlet.class 2009-Sep-04 03:12:45