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 |