comparison src/nabble/view/lib/JtpContextServlet.java @ 0:7ecd1a4ef557

add content
author Franklin Schmidt <fschmidt@gmail.com>
date Thu, 21 Mar 2019 19:15:52 -0600
parents
children
comparison
equal deleted inserted replaced
-1:000000000000 0:7ecd1a4ef557
1 package nabble.view.lib;
2
3 import fschmidt.util.servlet.*;
4 import fschmidt.util.java.ProcUtils;
5 import fschmidt.util.java.SimpleClassLoader;
6 import org.slf4j.Logger;
7 import org.slf4j.LoggerFactory;
8
9 import javax.servlet.ServletContext;
10 import javax.servlet.ServletException;
11 import javax.servlet.ServletOutputStream;
12 import javax.servlet.http.HttpServlet;
13 import javax.servlet.http.HttpServletRequest;
14 import javax.servlet.http.HttpServletResponse;
15 import javax.servlet.http.HttpServletResponseWrapper;
16 import java.io.File;
17 import java.io.IOException;
18 import java.io.PrintWriter;
19 import java.net.URL;
20 import java.util.Arrays;
21 import java.util.Collection;
22 import java.util.Collections;
23 import java.util.HashMap;
24 import java.util.HashSet;
25 import java.util.LinkedHashMap;
26 import java.util.LinkedList;
27 import java.util.Map;
28 import java.util.Set;
29
30
31 public final class JtpContextServlet extends HttpServlet implements JtpContext {
32 private static final Logger logger = LoggerFactory.getLogger(JtpContextServlet.class);
33
34 private static final Set<String> allowedMethods = new HashSet<String>(Arrays.asList(
35 "GET", "POST", "HEAD"
36 ));
37 private String base;
38 private boolean reload = false;
39 private boolean recompile = false;
40 private SimpleClassLoader.Filter filter = null;
41 private ClassLoader cl = null;
42 private Map<String,HttpServlet> map = new HashMap<String,HttpServlet>();
43 private long clTime;
44 private Object lock = new Object();
45 private HttpCache httpCache;
46 private boolean isCaching;
47 private String characterEncoding;
48 private Map<String, String> customHeaders = new HashMap<String, String>();
49 private UrlMapper urlMapper = new UrlMapper() {
50 public UrlMapping getUrlMapping(HttpServletRequest request) {
51 return null;
52 }
53 };
54 private Set<String> errorCache = null;
55 private Collection<String> ipList = null;
56 private static final String authKeyAttr = "authKey";
57 private static final String[] noModifyingEvents = new String[]{"_"};
58
59 public void setUrlMapper(UrlMapper urlMapper) {
60 this.urlMapper = urlMapper;
61 }
62
63 public HttpCache getHttpCache() {
64 return httpCache;
65 }
66
67 public void setHttpCache(HttpCache httpCache) {
68 this.httpCache = httpCache;
69 }
70
71 public void addCustomHeader(String key, String value) {
72 this.customHeaders.put(key, value);
73 }
74
75 public void unloadServlets() {
76 if( !reload )
77 throw new UnsupportedOperationException("'reload' must be set");
78 synchronized(lock) {
79 cl = new SimpleClassLoader(filter);
80 map = new HashMap<String,HttpServlet>();
81 clTime = System.currentTimeMillis();
82 }
83 }
84
85 public void setBase(String base) {
86 if( base==null )
87 throw new NullPointerException();
88 this.base = base;
89 }
90
91 public void init()
92 throws ServletException
93 {
94 ServletContext context = getServletContext();
95 String newBase = getInitParameter("base");
96 if( newBase != null )
97 setBase(newBase);
98 recompile = Boolean.valueOf(getInitParameter("recompile"));
99 reload = recompile || Boolean.valueOf(getInitParameter("reload"));
100 if( reload ) {
101 filter = new SimpleClassLoader.Filter(){
102 final String s = base + ".";
103 public boolean load(String className) {
104 return className.startsWith(s);
105 }
106 };
107 unloadServlets();
108 }
109 context.setAttribute(JtpContext.attrName,this);
110 String servletS = getInitParameter("servlet");
111 if( servletS != null ) {
112 throw new RuntimeException("the 'servlet' init parameter is no longer supported");
113 }
114 isCaching = "true".equalsIgnoreCase(getInitParameter("cache"));
115 if( isCaching ) {
116 if( httpCache==null ) {
117 logger.error("can't set init parameter 'cache' to true without httpCache");
118 System.exit(-1);
119 }
120 logger.info("cache");
121 }
122 characterEncoding = getInitParameter("characterEncoding");
123 {
124 String s = getInitParameter("timeLimit");
125 if( s != null )
126 timeLimit = Long.parseLong(s);
127 }
128 {
129 String s = getInitParameter("errorCacheSize");
130 if( s != null ) {
131 final int errorCacheSize = Integer.parseInt(s);
132 errorCache = Collections.synchronizedSet(Collections.newSetFromMap(new LinkedHashMap<String,Boolean>(){
133 protected boolean removeEldestEntry(Map.Entry eldest) {
134 return size() > errorCacheSize;
135 }
136 }));
137 }
138 }
139 {
140 String s = getInitParameter("ipListSize");
141 if( s != null ) {
142 final int ipListSize = Integer.parseInt(s);
143 ipList = Collections.synchronizedList(new LinkedList<String>() {
144 public boolean add(String s) {
145 if( contains(s) )
146 return false;
147 super.add(s);
148 if( size() > ipListSize )
149 removeFirst();
150 return true;
151 }
152 });
153 }
154 }
155 }
156
157 private boolean isInErrorCache(String s) {
158 return errorCache==null || !errorCache.add(s);
159 }
160
161 private boolean isInIpList(String ip) {
162 return ipList!=null && !ipList.add(ip);
163 }
164
165 public static interface DestroyListener {
166 public void destroyed();
167 }
168
169 private DestroyListener destroyListener = null;
170
171 public void addDestroyListener(DestroyListener dl) {
172 synchronized(lock) {
173 if( destroyListener!=null )
174 throw new RuntimeException("only one DestroyListener allowed");
175 destroyListener = dl;
176 }
177 }
178
179 public void destroy() {
180 synchronized(lock) {
181 if( destroyListener != null )
182 destroyListener.destroyed();
183 }
184 }
185
186 public static final class RequestAndResponse {
187 public final HttpServletRequest request;
188 public final HttpServletResponse response;
189
190 public RequestAndResponse(HttpServletRequest request,HttpServletResponse response) {
191 this.request = request;
192 this.response = response;
193 }
194 }
195
196 public static interface CustomWrappers {
197 public RequestAndResponse wrap(HttpServletRequest request, HttpServletResponse response);
198 }
199
200 private CustomWrappers customWrappers;
201
202 public void setCustomWrappers(CustomWrappers customWrappers) {
203 this.customWrappers = customWrappers;
204 }
205
206 private static String hideNull(String s) {
207 return s==null ? "" : s;
208 }
209
210 private String getServletPath(HttpServletRequest request) {
211 return request.getServletPath() + hideNull(request.getPathInfo());
212 }
213
214 protected void service(HttpServletRequest request,HttpServletResponse response)
215 throws ServletException, IOException
216 {
217 final TimeLimit tl = startTimeLimit(request);
218 response = new HttpServletResponseWrapper(response) {
219 PrintWriter writer = null;
220 ServletOutputStream out = null;
221
222 public PrintWriter getWriter()
223 throws java.io.IOException
224 {
225 if( writer==null ) {
226 writer = new PrintWriter(super.getWriter()) {
227 public void write(String s,int off,int len) {
228 long t = System.currentTimeMillis();
229 super.write(s,off,len);
230 tl.ioTime += System.currentTimeMillis() - t;
231 }
232 public void write(char[] buf,int off,int len) {
233 long t = System.currentTimeMillis();
234 super.write(buf,off,len);
235 tl.ioTime += System.currentTimeMillis() - t;
236 }
237 public void write(int c) {
238 long t = System.currentTimeMillis();
239 super.write(c);
240 tl.ioTime += System.currentTimeMillis() - t;
241 }
242 public void flush() {
243 long t = System.currentTimeMillis();
244 super.flush();
245 tl.ioTime += System.currentTimeMillis() - t;
246 }
247 public void println() {
248 long t = System.currentTimeMillis();
249 super.println();
250 tl.ioTime += System.currentTimeMillis() - t;
251 }
252 };
253 }
254 return writer;
255 }
256
257 public ServletOutputStream getOutputStream()
258 throws java.io.IOException
259 {
260 if( out==null ) {
261 final ServletOutputStream sos = super.getOutputStream();
262 out = new ServletOutputStream() {
263 public void write(byte[] b,int off,int len) throws IOException {
264 long t = System.currentTimeMillis();
265 sos.write(b,off,len);
266 tl.ioTime += System.currentTimeMillis() - t;
267 }
268 public void write(byte[] b) throws IOException {
269 long t = System.currentTimeMillis();
270 sos.write(b);
271 tl.ioTime += System.currentTimeMillis() - t;
272 }
273 public void write(int c) throws IOException {
274 long t = System.currentTimeMillis();
275 sos.write(c);
276 tl.ioTime += System.currentTimeMillis() - t;
277 }
278 public void flush() throws IOException {
279 long t = System.currentTimeMillis();
280 sos.flush();
281 tl.ioTime += System.currentTimeMillis() - t;
282 }
283 };
284 }
285 return out;
286 }
287
288 public void sendError(int sc) throws IOException {
289 long t = System.currentTimeMillis();
290 super.sendError(sc);
291 tl.ioTime += System.currentTimeMillis() - t;
292 }
293
294 public void sendRedirect(String location) throws IOException {
295 if( containsHeader("Expires") )
296 setHeader("Expires",null);
297 if( containsHeader("Last-Modified") )
298 setHeader("Last-Modified",null);
299 if( containsHeader("Etag") )
300 setHeader("Etag",null);
301 if( containsHeader("Cache-Control") )
302 setHeader("Cache-Control",null);
303 if( containsHeader("Content-Type") )
304 setHeader("Content-Type",null);
305 if( containsHeader("Content-Length") )
306 // setHeader("Content-Length",null);
307 setContentLength(0);
308 super.sendRedirect(location);
309 }
310 };
311 service2(request,response);
312 checkTimeLimit(request);
313 }
314
315 private void service2(HttpServletRequest request, HttpServletResponse response)
316 throws ServletException, IOException
317 {
318 if( !allowedMethods.contains(request.getMethod()) ) {
319 response.sendError(HttpServletResponse.SC_METHOD_NOT_ALLOWED);
320 return;
321 }
322 // String contextPath = request.getContextPath();
323 // String contextUrl = ServletUtils.getContextURL(request);
324
325 // First we set the character encoding because any manipulation
326 // of request parameters will break without this.
327 response.setHeader("Content-Type","text/html; charset=utf-8"); // default, servlet can override
328 if( characterEncoding != null ) {
329 response.setCharacterEncoding(characterEncoding);
330 request.setCharacterEncoding(characterEncoding);
331 }
332
333 HttpServlet servlet;
334 String path = getServletPath(request);
335
336 UrlMapping urlMapping = urlMapper.getUrlMapping(request);
337 if( urlMapping != null ) {
338 try {
339 servlet = getServletFromClass(urlMapping.servletClass.getName());
340 } catch(ClassNotFoundException e) {
341 throw new RuntimeException(e);
342 }
343 final Map params = urlMapping.parameterMap;
344 request = new BetterRequestWrapper(request) {
345 public Map getParameterMap() {
346 return params;
347 }
348 };
349 } else {
350 try {
351 servlet = getServlet(path);
352 } catch(ClassNotFoundException e) {
353 response.sendError(HttpServletResponse.SC_NOT_FOUND);
354 String agent = request.getHeader("user-agent");
355 String referer = request.getHeader("referer");
356 String remote = getClientIpAddr(request);
357 String msg = request.getRequestURL()+" referer="+referer+" user-agent="+agent+" remote="+remote;
358 if( referer==null ) {
359 logger.info(msg,e);
360 } else {
361 logger.warn(msg,e);
362 }
363 return;
364 }
365 }
366
367 // Custom headers
368 addCustomHeaders(response);
369
370 AuthorizingServlet auth = servlet instanceof AuthorizingServlet ? (AuthorizingServlet)servlet : null;
371 if( isCaching ) {
372 String etagS = request.getHeader("If-None-Match");
373 if( etagS != null ) {
374 String prevEtag = null;
375 for( String etag : etagS.split("\\s*,\\s*") ) {
376 if( etag.equals(prevEtag) )
377 continue;
378 prevEtag = etag;
379 if( etag.length()>=2 && etag.charAt(0)=='"' && etag.charAt(etag.length()-1)=='"' )
380 etag = etag.substring(1,etag.length()-1);
381 String authKey = null;
382 if( etag.length()>=2 && etag.charAt(0)=='[' ) {
383 int i = etag.indexOf(']');
384 if( i > 0 ) {
385 if( auth != null )
386 authKey = etag.substring(1,i);
387 etag = etag.substring(i+1);
388 }
389 }
390 String[] events = etag.split("~");
391 long lastModified = getLastModified(events);
392 try {
393 if( lastModified <= request.getDateHeader("If-Modified-Since") ) {
394 if( authKey==null || authorize(auth,authKey,request,response) )
395 response.sendError(HttpServletResponse.SC_NOT_MODIFIED);
396 return;
397 }
398 } catch(RuntimeException e) {
399 handleException(request,e);
400 }
401 }
402 }
403 }
404 String authKey = auth==null ? null : getAuthorizationKey(auth,request);
405 if( authKey != null ) {
406 if( !authorize(auth,authKey,request,response) )
407 return;
408 request.setAttribute(authKeyAttr,authKey);
409 }
410
411 if( servlet instanceof CanonicalUrl ) {
412 CanonicalUrl srv = (CanonicalUrl)servlet;
413 StringBuffer currentUrl = request.getRequestURL();
414 int i = currentUrl.indexOf(";");
415 if( i != -1 )
416 currentUrl.setLength(i);
417 String query = request.getQueryString();
418 if( query != null )
419 currentUrl.append( '?' ).append( query );
420 try {
421 String canonicalUrl = srv.getCanonicalUrl(request);
422 if( canonicalUrl != null && !stripScheme(currentUrl.toString()).equals(stripScheme(canonicalUrl)) ) {
423 response.setHeader("Location",canonicalUrl);
424 response.sendError( HttpServletResponse.SC_MOVED_PERMANENTLY );
425 return;
426 }
427 } catch(RuntimeException e) {
428 logger.warn("couldn't get canonical url",e);
429 }
430 }
431
432 request.setAttribute("servlet",servlet);
433
434 try {
435 if (customWrappers != null) {
436 RequestAndResponse rr = customWrappers.wrap(request, response);
437 request = rr.request;
438 response = rr.response;
439 }
440 servlet.service(request,response);
441 } catch(RuntimeException e) {
442 handleException(request,e);
443 } catch(ServletException e) {
444 handleException(request,e);
445 }
446 }
447
448 private static String stripScheme(String url) {
449 return url.substring(url.indexOf(':'));
450 }
451
452 public void setEtag( HttpServletRequest request, HttpServletResponse response, String... modifyingEvents ) {
453 if( modifyingEvents.length == 0 )
454 modifyingEvents = noModifyingEvents;
455 StringBuilder buf = new StringBuilder();
456 String authKey = (String)request.getAttribute(authKeyAttr);
457 if( authKey != null )
458 buf.append( '[' ).append( authKey).append( ']' );
459 buf.append( modifyingEvents[0] );
460 for( int i=1; i<modifyingEvents.length; i++ ) {
461 buf.append( '~' ).append( modifyingEvents[i] );
462 }
463 response.setHeader("Etag",buf.toString());
464 long lastModified = getLastModified(modifyingEvents);
465 response.setDateHeader("Last-Modified",lastModified);
466 response.setHeader("Cache-Control","max-age=0");
467 }
468
469 private boolean authorize(AuthorizingServlet auth,String authKey,HttpServletRequest request,HttpServletResponse response)
470 throws IOException, ServletException
471 {
472 try {
473 if (customWrappers != null) {
474 RequestAndResponse rr = customWrappers.wrap(request, response);
475 request = rr.request;
476 response = rr.response;
477 }
478 return auth.authorize(authKey,request,response);
479 } catch(RuntimeException e) {
480 handleException(request,e);
481 } catch(ServletException e) {
482 handleException(request,e);
483 }
484 throw new RuntimeException("never");
485 }
486
487 private String getAuthorizationKey(AuthorizingServlet auth,HttpServletRequest request)
488 throws ServletException
489 {
490 try {
491 return auth.getAuthorizationKey(request);
492 } catch(RuntimeException e) {
493 handleException(request,e);
494 } catch(ServletException e) {
495 handleException(request,e);
496 }
497 return null; // never gets here
498 }
499
500 private long getLastModified(String[] modifyingEvents) {
501 long[] lastModifieds = httpCache.lastModifieds(modifyingEvents);
502 long lastModified = lastModifieds[0];
503 for( int i=1; i<lastModifieds.length; i++ ) {
504 long lm = lastModifieds[i];
505 if( lastModified < lm )
506 lastModified = lm;
507 }
508 return lastModified;
509 }
510
511 /** Adds all custom headers to the response object. */
512 private void addCustomHeaders(HttpServletResponse response) {
513 Set<Map.Entry<String, String>> entries = this.customHeaders.entrySet();
514 for (Map.Entry<String, String> entry : entries) {
515 response.setHeader(entry.getKey(), entry.getValue());
516 }
517 }
518
519 private void handleException(HttpServletRequest request,RuntimeException e)
520 throws ServletException
521 {
522 JtpRuntimeException rte;
523 try {
524 String agent = request.getHeader("user-agent");
525 if( agent == null )
526 throw new JtpServletException(request,"null agent",e);
527 if (!isValidAgent(agent))
528 throw new JtpServletException(request, "bad agent " + agent, e);
529 String remote = getClientIpAddr(request);
530 String referer = request.getHeader("referer");
531 StringBuilder buf = new StringBuilder()
532 .append( "method=" ).append( request.getMethod() )
533 .append( " user-agent=" ).append( agent )
534 .append( " referer=" ).append( referer )
535 .append( " remote=" ).append( remote )
536 ;
537 String etag = request.getHeader("If-None-Match");
538 if( etag != null )
539 buf.append( " etag=[" ).append( etag ).append( "]" );
540 if( referer==null || isInIpList(remote) )
541 throw new JtpServletException(request,buf.toString(),e);
542 rte = new JtpRuntimeException(request,buf.toString(),e);
543 } catch(RuntimeException e2) {
544 logger.error("failed to handle",e);
545 throw e2;
546 }
547 throw rte;
548 }
549
550 private static void handleException(HttpServletRequest request,ServletException e)
551 throws ServletException
552 {
553 String agent = request.getHeader("user-agent");
554 throw new JtpServletException(request,"user-agent="+agent+" method="+request.getMethod()+" referer="+request.getHeader("referer"),e);
555 }
556
557 private static class JtpRuntimeException extends RuntimeException {
558 private JtpRuntimeException(HttpServletRequest request,String msg,RuntimeException e) {
559 super("url="+getCurrentURL(request)+" "+msg,e);
560 }
561 }
562
563 private static class JtpServletException extends ServletException {
564 private JtpServletException(HttpServletRequest request,String msg,Exception e) {
565 super("url="+getCurrentURL(request)+" "+msg,e);
566 }
567 }
568
569 // work-around jetty bug
570 private static String getCurrentURL(HttpServletRequest request) {
571 try {
572 return ServletUtils.getCurrentURL(request);
573 } catch(RuntimeException e) {
574 logger.warn("jetty screwed up",e);
575 return "[failed]";
576 }
577 }
578
579 private static boolean isValidAgent(String agent) {
580 if (agent == null)
581 return false;
582 for (String badAgent : badAgents) {
583 if (agent.indexOf(badAgent) >= 0)
584 return false;
585 }
586 return true;
587 }
588
589 private static final String[] badAgents = new String[]{
590 "MJ12bot",
591 "WISEnutbot",
592 "Win98", // not worth handling these
593 "Windows 98",
594 "Windows 95",
595 "RixBot",
596 "User-Agent", // from corrupt header
597 "Firefox/0", // ancient version of Firefox
598 "Firefox/2.", // ancient version of Firefox
599 "Firefox/3.", // ancient version of Firefox
600 "Opera 7.", // ancient version of Opera
601 "Opera/7.",
602 "Opera 8.",
603 "Opera/8.",
604 "Opera/9.",
605 "TwitterFeed 3",
606 "NAVER Blog Rssbot",
607 "AOL 9.0",
608 "rssreader@newstin.com",
609 "PHPCrawl",
610 "MSIE 2.",
611 "MSIE 4.",
612 "MSIE 5.",
613 "MSIE 6.",
614 "MSIE 7.0",
615 "Mozilla/0.",
616 "Mozilla/2.0",
617 "Mozilla/3.0",
618 "Mozilla/4.6",
619 "Mozilla/4.7",
620 "RSSIncludeBot/1.0", // cause exceptions in xml feeds
621 "Powermarks",
622 "GenwiFeeder",
623 "Akregator",
624 "ia_archiver",
625 "Atomic_Email_Hunter",
626 "Yahoo! Slurp",
627 "Python-urllib",
628 "BlackBerry",
629 "SimplePie", // Feeds parser
630 "www.webintegration.at", // crazy bot
631 "www.run4dom.com", // crazy bot
632 "zia-httpmirror",
633 "POE-Component-Client-HTTP",
634 "anonymous",
635 "Sosospider",
636 "Java/1.6",
637 "Shareaza",
638 "Jakarta Commons-HttpClient",
639 "Apache-HttpClient",
640 "Baiduspider",
641 "bingbot",
642 "MLBot", // www.metadatalabs.com/mlbot
643 "www.vbseo.com",
644 "yacybot", // yacy.net/bot.html
645 "SearchBot"
646 };
647
648 private static boolean isBot(String agent) {
649 if (agent == null)
650 return false;
651 for (String bot : bots) {
652 if (agent.indexOf(bot) >= 0)
653 return true;
654 }
655 return false;
656 }
657
658 private static final String[] bots = new String[]{
659 "Googlebot"
660 };
661
662 private HttpServlet getServlet(String path)
663 throws ServletException, ClassNotFoundException, IOException
664 {
665 int i = path.lastIndexOf('.');
666 if( i == -1 )
667 throw new ClassNotFoundException(path);
668 return getServletFromClass(
669 base + path.substring(0,i).replace('/','.')
670 );
671 }
672
673 private HttpServlet getServletFromClass(String cls)
674 throws ClassNotFoundException
675 {
676 synchronized(lock) {
677 if( reload && hasChanged(cls) ) {
678 unloadServlets();
679 }
680 HttpServlet srv = map.get(cls);
681 if( srv==null ) {
682 try {
683 Class clas = reload ? cl.loadClass(cls) : Class.forName(cls);
684 srv = (HttpServlet)clas.newInstance();
685 } catch(IllegalAccessException e) {
686 throw new RuntimeException(e);
687 } catch(InstantiationException e) {
688 throw new RuntimeException(e);
689 }
690 try {
691 srv.init(this);
692 } catch(ServletException e) {
693 throw new RuntimeException(e);
694 }
695 map.put(cls,srv);
696 }
697 return srv;
698 }
699 }
700
701 private boolean hasChanged(String cls) {
702 try {
703 URL url = cl.getResource( SimpleClassLoader.classToResource(cls) );
704 if( url==null )
705 return true;
706 File file = new File(url.getPath());
707 if( recompile ) {
708 String path = file.toString();
709 if( !path.endsWith(".class") )
710 throw new RuntimeException();
711 File dir = file.getParentFile();
712 String base = path.substring(0,path.length()-6);
713 File source = new File( base + ".jtp" );
714 if( source.lastModified() > clTime ) {
715 Process proc = Runtime.getRuntime().exec(new String[]{
716 "java", "fschmidt.tools.Jtp", source.getName()
717 },null,dir);
718 ProcUtils.checkProc(proc);
719 }
720 source = new File( base + ".java" );
721 if( source.lastModified() > clTime ) {
722 Process proc = Runtime.getRuntime().exec(new String[]{
723 "javac", "-g", source.getName()
724 },null,dir);
725 ProcUtils.checkProc(proc);
726 }
727 }
728 return file.lastModified() > clTime;
729 } catch(IOException e) {
730 throw new RuntimeException(e);
731 }
732 }
733
734
735 private long timeLimit = 0;
736 private static final String timeLimitAttr = "time-limit";
737
738 private static class TimeLimit {
739 long timeLimit;
740 final long startTime = System.currentTimeMillis();
741 long ioTime = 0L;
742
743 TimeLimit(long timeLimit) {
744 this.timeLimit = timeLimit;
745 }
746 }
747
748 public long getTimeLimit() {
749 return timeLimit;
750 }
751
752 public void setTimeLimit(long timeLimit) {
753 this.timeLimit = timeLimit;
754 }
755
756 private TimeLimit startTimeLimit(HttpServletRequest request) {
757 TimeLimit tl = new TimeLimit(timeLimit);
758 request.setAttribute( timeLimitAttr, tl );
759 return tl;
760 }
761
762 public void setTimeLimit(HttpServletRequest request,long timeLimit) {
763 TimeLimit tl = (TimeLimit)request.getAttribute(timeLimitAttr);
764 tl.timeLimit = timeLimit;
765 }
766
767 private void checkTimeLimit(HttpServletRequest request) {
768 TimeLimit tl = (TimeLimit)request.getAttribute(timeLimitAttr);
769 if( tl.timeLimit == 0L )
770 return;
771 long time = System.currentTimeMillis() - tl.startTime - tl.ioTime;
772 if( time > tl.timeLimit ) {
773 float free = Runtime.getRuntime().freeMemory();
774 float total = Runtime.getRuntime().totalMemory();
775 float used = (total - free) * 100f;
776 logger.error(ServletUtils.getCurrentURL(request,100) + " took " + time + " ms | " + String.format("%.1f",used/total) + '%');
777 /*
778 Scheduler scheduler = TheScheduler.get();
779 if( scheduler instanceof ProfilingScheduler ) {
780 ProfilingScheduler profilingScheduler = (ProfilingScheduler)scheduler;
781 if( profilingScheduler.getMode()==ProfilingScheduler.Mode.FOREGROUND ) {
782 profilingScheduler.captureCPUSnapshot();
783 }
784 }
785 */
786 }
787 }
788
789 public static String getClientIpAddr(HttpServletRequest request) {
790 String ip = request.getHeader("X-Real-IP");
791 if( ip == null )
792 ip = request.getRemoteAddr();
793 return ip;
794 }
795
796 }