golf 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (141) hide show
  1. data/.gitignore +10 -0
  2. data/Gemfile +6 -0
  3. data/Gemfile.lock +21 -0
  4. data/Rakefile +12 -0
  5. data/bin/golf +8 -0
  6. data/golf-java/README.markdown +41 -0
  7. data/golf-java/THANKS.markdown +14 -0
  8. data/golf-java/build/classes.zip +0 -0
  9. data/golf-java/build/com/thinkminimo/golf/GolfResource$MimeMapping$MimeMappingSingleton.class +0 -0
  10. data/golf-java/build/com/thinkminimo/golf/GolfResource$MimeMapping.class +0 -0
  11. data/golf-java/build/com/thinkminimo/golf/GolfResource.class +0 -0
  12. data/golf-java/build/com/thinkminimo/golf/GolfServlet$1.class +0 -0
  13. data/golf-java/build/com/thinkminimo/golf/GolfServlet$GolfContext.class +0 -0
  14. data/golf-java/build/com/thinkminimo/golf/GolfServlet$GolfParams.class +0 -0
  15. data/golf-java/build/com/thinkminimo/golf/GolfServlet$GolfSession.class +0 -0
  16. data/golf-java/build/com/thinkminimo/golf/GolfServlet$PermanentRedirectException.class +0 -0
  17. data/golf-java/build/com/thinkminimo/golf/GolfServlet$RedirectException.class +0 -0
  18. data/golf-java/build/com/thinkminimo/golf/GolfServlet$StoredJSVM.class +0 -0
  19. data/golf-java/build/com/thinkminimo/golf/GolfServlet.class +0 -0
  20. data/golf-java/build/com/thinkminimo/golf/JsonpTunnel.class +0 -0
  21. data/golf-java/build/com/thinkminimo/golf/Main$1.class +0 -0
  22. data/golf-java/build/com/thinkminimo/golf/Main$RingList.class +0 -0
  23. data/golf-java/build/com/thinkminimo/golf/Main.class +0 -0
  24. data/golf-java/build/com/thinkminimo/golf/ProxyServlet.class +0 -0
  25. data/golf-java/build/com/yahoo/platform/yui/compressor/CssCompressor.class +0 -0
  26. data/golf-java/build/com/yahoo/platform/yui/compressor/JarClassLoader.class +0 -0
  27. data/golf-java/build/com/yahoo/platform/yui/compressor/JavaScriptCompressor.class +0 -0
  28. data/golf-java/build/com/yahoo/platform/yui/compressor/JavaScriptIdentifier.class +0 -0
  29. data/golf-java/build/com/yahoo/platform/yui/compressor/JavaScriptToken.class +0 -0
  30. data/golf-java/build/com/yahoo/platform/yui/compressor/ScriptOrFnScope.class +0 -0
  31. data/golf-java/build/depends.zip +0 -0
  32. data/golf-java/build/golf +2 -0
  33. data/golf-java/build/org/json/JSONArray.class +0 -0
  34. data/golf-java/build/org/json/JSONException.class +0 -0
  35. data/golf-java/build/org/json/JSONObject$1.class +0 -0
  36. data/golf-java/build/org/json/JSONObject$Null.class +0 -0
  37. data/golf-java/build/org/json/JSONObject.class +0 -0
  38. data/golf-java/build/org/json/JSONString.class +0 -0
  39. data/golf-java/build/org/json/JSONStringer.class +0 -0
  40. data/golf-java/build/org/json/JSONTokener.class +0 -0
  41. data/golf-java/build/org/json/JSONWriter.class +0 -0
  42. data/golf-java/build/resources.zip +0 -0
  43. data/golf-java/build.xml +174 -0
  44. data/golf-java/dist/golf.zip +0 -0
  45. data/golf-java/lib/ant-launcher.jar +0 -0
  46. data/golf-java/lib/ant.jar +0 -0
  47. data/golf-java/lib/commons-codec-1.4.jar +0 -0
  48. data/golf-java/lib/commons-collections-3.2.1.jar +0 -0
  49. data/golf-java/lib/commons-fileupload-1.2.1.jar +0 -0
  50. data/golf-java/lib/commons-httpclient-3.1.jar +0 -0
  51. data/golf-java/lib/commons-io-1.4.jar +0 -0
  52. data/golf-java/lib/commons-lang-2.4.jar +0 -0
  53. data/golf-java/lib/commons-logging-1.1.1.jar +0 -0
  54. data/golf-java/lib/cssparser-0.9.5.jar +0 -0
  55. data/golf-java/lib/getopt-0.1-dev.jar +0 -0
  56. data/golf-java/lib/htmlunit-2.6.jar +0 -0
  57. data/golf-java/lib/htmlunit-core-js-2.6.jar +0 -0
  58. data/golf-java/lib/java-xmlbuilder-1.jar +0 -0
  59. data/golf-java/lib/jets3t-0.7.0.jar +0 -0
  60. data/golf-java/lib/jetty-6.1.15.jar +0 -0
  61. data/golf-java/lib/jetty-util-6.1.15.jar +0 -0
  62. data/golf-java/lib/log4j-1.2.15.jar +0 -0
  63. data/golf-java/lib/nekohtml-1.9.13.jar +0 -0
  64. data/golf-java/lib/sac-1.3.jar +0 -0
  65. data/golf-java/lib/serializer-2.7.1.jar +0 -0
  66. data/golf-java/lib/servlet-api-2.5-20081211.jar +0 -0
  67. data/golf-java/lib/xalan-2.7.1.jar +0 -0
  68. data/golf-java/lib/xercesImpl-2.9.1.jar +0 -0
  69. data/golf-java/lib/xml-apis-1.3.04.jar +0 -0
  70. data/golf-java/resources/app_error.html +60 -0
  71. data/golf-java/resources/error.html +29 -0
  72. data/golf-java/resources/forcebot.txt +0 -0
  73. data/golf-java/resources/forceclient.txt +0 -0
  74. data/golf-java/resources/forceproxy.txt +0 -0
  75. data/golf-java/resources/head.html +0 -0
  76. data/golf-java/resources/jquery.address.js +439 -0
  77. data/golf-java/resources/jquery.golf.js +945 -0
  78. data/golf-java/resources/jquery.js +4376 -0
  79. data/golf-java/resources/jsdetect.html +23 -0
  80. data/golf-java/resources/loading.gif +0 -0
  81. data/golf-java/resources/new.html +45 -0
  82. data/golf-java/resources/new.static.html +45 -0
  83. data/golf-java/resources/noscript.forceclient.html +11 -0
  84. data/golf-java/resources/noscript.html +18 -0
  85. data/golf-java/resources/noscript.static.html +15 -0
  86. data/golf-java/resources/project.xml +21 -0
  87. data/golf-java/resources/proxy_project.xml +11 -0
  88. data/golf-java/resources/proxy_web.xml +40 -0
  89. data/golf-java/resources/static_project.xml +37 -0
  90. data/golf-java/resources/version +1 -0
  91. data/golf-java/resources/web.xml +36 -0
  92. data/golf-java/resources/welcome2golf.html +50 -0
  93. data/golf-java/src/com/thinkminimo/golf/GolfResource.java +582 -0
  94. data/golf-java/src/com/thinkminimo/golf/GolfServlet.java +1055 -0
  95. data/golf-java/src/com/thinkminimo/golf/JsonpTunnel.java +86 -0
  96. data/golf-java/src/com/thinkminimo/golf/Main.java +1299 -0
  97. data/golf-java/src/com/thinkminimo/golf/ProxyServlet.java +577 -0
  98. data/golf-java/src/com/yahoo/platform/yui/compressor/CssCompressor.java +188 -0
  99. data/golf-java/src/com/yahoo/platform/yui/compressor/JarClassLoader.java +158 -0
  100. data/golf-java/src/com/yahoo/platform/yui/compressor/JavaScriptCompressor.java +1281 -0
  101. data/golf-java/src/com/yahoo/platform/yui/compressor/JavaScriptIdentifier.java +55 -0
  102. data/golf-java/src/com/yahoo/platform/yui/compressor/JavaScriptToken.java +28 -0
  103. data/golf-java/src/com/yahoo/platform/yui/compressor/ScriptOrFnScope.java +160 -0
  104. data/golf-java/src/org/json/JSONArray.java +934 -0
  105. data/golf-java/src/org/json/JSONException.java +27 -0
  106. data/golf-java/src/org/json/JSONObject.java +1550 -0
  107. data/golf-java/src/org/json/JSONString.java +18 -0
  108. data/golf-java/src/org/json/JSONStringer.java +78 -0
  109. data/golf-java/src/org/json/JSONTokener.java +422 -0
  110. data/golf-java/src/org/json/JSONWriter.java +323 -0
  111. data/golf-java/test/client/golftest/README.markdown +3 -0
  112. data/golf-java/test/client/golftest/components/com/thinkminimo/golf/test/Harness.css +114 -0
  113. data/golf-java/test/client/golftest/components/com/thinkminimo/golf/test/Harness.html +17 -0
  114. data/golf-java/test/client/golftest/components/com/thinkminimo/golf/test/Harness.js +81 -0
  115. data/golf-java/test/client/golftest/components/com/thinkminimo/golf/test/Harness.res/asc.gif +0 -0
  116. data/golf-java/test/client/golftest/components/com/thinkminimo/golf/test/Harness.res/bg.gif +0 -0
  117. data/golf-java/test/client/golftest/components/com/thinkminimo/golf/test/Harness.res/desc.gif +0 -0
  118. data/golf-java/test/client/golftest/components/com/thinkminimo/golf/test/Harness.res/test/test.html +1 -0
  119. data/golf-java/test/client/golftest/controller.js +131 -0
  120. data/golf-java/test/client/golftest/forceclient.txt +0 -0
  121. data/golf-java/test/client/golftest/forceproxy.txt +0 -0
  122. data/golf-java/test/client/golftest/head.html +1 -0
  123. data/golf-java/test/client/golftest/scripts/jquery.tablesort.js +75 -0
  124. data/golf-java/test/client/golftest/styles/style.css +18 -0
  125. data/golf-java/test/client/golftest/test/test.html +1 -0
  126. data/golf.gemspec +24 -0
  127. data/lib/golf/cli.rb +32 -0
  128. data/lib/golf/compiler.rb +12 -0
  129. data/lib/golf/rack.rb +17 -0
  130. data/lib/golf/version.rb +3 -0
  131. data/lib/golf.rb +6 -0
  132. data/template/Gemfile +5 -0
  133. data/template/config.ru +7 -0
  134. data/template/golfapp/components/Test/Test.html +22 -0
  135. data/template/golfapp/components/Test/Test.res/myfile.txt +1 -0
  136. data/template/golfapp/controller.js +10 -0
  137. data/template/golfapp/plugins/mylib.js +12 -0
  138. data/test/test_compiler.rb +10 -0
  139. data/test/test_helper.rb +6 -0
  140. data/test/test_rack.rb +17 -0
  141. metadata +208 -0
@@ -0,0 +1,1055 @@
1
+ package com.thinkminimo.golf;
2
+
3
+ import org.json.JSONStringer;
4
+ import org.json.JSONException;
5
+
6
+ import java.io.*;
7
+ import java.util.concurrent.ConcurrentHashMap;
8
+ import java.util.concurrent.atomic.AtomicBoolean;
9
+ import java.util.*;
10
+ import java.util.regex.Pattern;
11
+ import net.sourceforge.htmlunit.corejs.javascript.*;
12
+
13
+ import java.net.*;
14
+
15
+ import javax.servlet.*;
16
+ import javax.servlet.http.*;
17
+
18
+ import org.mortbay.jetty.servlet.DefaultServlet;
19
+
20
+ import com.gargoylesoftware.htmlunit.*;
21
+ import com.gargoylesoftware.htmlunit.html.*;
22
+ import com.gargoylesoftware.htmlunit.xml.*;
23
+ import com.gargoylesoftware.htmlunit.javascript.*;
24
+
25
+ /**
26
+ * Golf servlet class!
27
+ */
28
+ public class GolfServlet extends HttpServlet {
29
+
30
+ public static final int LOG_ALL = 0;
31
+ public static final int LOG_TRACE = 1;
32
+ public static final int LOG_DEBUG = 2;
33
+ public static final int LOG_INFO = 3;
34
+ public static final int LOG_WARN = 4;
35
+ public static final int LOG_ERROR = 5;
36
+ public static final int LOG_FATAL = 6;
37
+ public static final int LOG_NONE = 999;
38
+
39
+ public static final int JSVM_TIMEOUT = 10000;
40
+
41
+ private class StoredJSVM {
42
+ public WebClient client;
43
+ public HtmlPage lastPage;
44
+ public long lastAccessTime;
45
+
46
+ StoredJSVM(WebClient client) {
47
+ this.client = client;
48
+ this.lastPage = null;
49
+ this.lastAccessTime = (new Date()).getTime();
50
+ }
51
+ }
52
+
53
+ public static class RedirectException extends Exception {
54
+ public RedirectException(String msg) {
55
+ super(msg);
56
+ }
57
+ }
58
+
59
+ public static class PermanentRedirectException extends RedirectException {
60
+ public PermanentRedirectException(String msg) {
61
+ super(msg);
62
+ }
63
+ }
64
+
65
+ private class GolfSession {
66
+ private HttpSession mSess;
67
+
68
+ public GolfSession(HttpServletRequest req) {
69
+ mSess = req.getSession(true);
70
+ }
71
+
72
+ private String get(String name) {
73
+ return (String) mSess.getAttribute(name);
74
+ }
75
+ private void set(String name, String value) {
76
+ mSess.setAttribute(name, value);
77
+ }
78
+
79
+ public Integer getSeq() {
80
+ try {
81
+ return Integer.parseInt(get("golf"));
82
+ } catch (NumberFormatException e) { }
83
+ return null;
84
+ }
85
+ public void setSeq(Integer value) {
86
+ set("golf", String.valueOf(value));
87
+ }
88
+
89
+ public Boolean getJs() {
90
+ return get("js") == null ? null : Boolean.parseBoolean(get("js"));
91
+ }
92
+ public void setJs(boolean value) {
93
+ set("js", String.valueOf(value));
94
+ }
95
+
96
+ public String getIpAddr() {
97
+ return get("ipaddr");
98
+ }
99
+ public void setIpAddr(String value) {
100
+ set("ipaddr", value);
101
+ }
102
+
103
+ public String getLastUrl() {
104
+ return get("lasturl");
105
+ }
106
+ public void setLastUrl(String value) {
107
+ set("lasturl", value);
108
+ }
109
+
110
+ public String getLastEvent() {
111
+ return get("lastevent");
112
+ }
113
+ public void setLastEvent(String value) {
114
+ set("lastevent", value);
115
+ }
116
+
117
+ public String getLastTarget() {
118
+ return get("lasttarget");
119
+ }
120
+ public void setLastTarget(String value) {
121
+ set("lasttarget", value);
122
+ }
123
+
124
+ public Boolean getForceClient() {
125
+ return get("forceclient") == null
126
+ ? null
127
+ : Boolean.parseBoolean(get("forceclient"));
128
+ }
129
+ public void setForceClient(Boolean value) {
130
+ set("forceclient", String.valueOf(value));
131
+ }
132
+ public Boolean getForceProxy() {
133
+ return get("forceproxy") == null
134
+ ? null
135
+ : Boolean.parseBoolean(get("forceproxy"));
136
+ }
137
+ public void setForceProxy(Boolean value) {
138
+ set("forceproxy", String.valueOf(value));
139
+ }
140
+ public Boolean getForceBot() {
141
+ return get("forceproxy") == null
142
+ ? null
143
+ : Boolean.parseBoolean(get("forcebot"));
144
+ }
145
+ public void setForceBot(Boolean value) {
146
+ set("forcebot", String.valueOf(value));
147
+ }
148
+ }
149
+
150
+ private class GolfParams {
151
+ private String mEvent = null;
152
+ private String mTarget = null;
153
+ private Boolean mForce = false;
154
+ private Integer mSeq = -1;
155
+ private Boolean mJs = false;
156
+ private String mPath = null;
157
+ private Boolean mReload = false;
158
+
159
+ public GolfParams(HttpServletRequest req) {
160
+ mEvent = req.getParameter("event");
161
+ mTarget = req.getParameter("target");
162
+ mForce = req.getParameter("force") == null
163
+ ? null
164
+ : Boolean.parseBoolean(req.getParameter("force"));
165
+ mSeq = req.getParameter("golf") == null
166
+ ? null
167
+ : Integer.valueOf(req.getParameter("golf"));
168
+ mJs = req.getParameter("js") == null
169
+ ? null
170
+ : Boolean.parseBoolean(req.getParameter("js"));
171
+ mPath = req.getParameter("path");
172
+ mReload = req.getParameter("reload") == null
173
+ ? null
174
+ : Boolean.parseBoolean(req.getParameter("reload"));
175
+ }
176
+
177
+ public String getEvent() { return mEvent; }
178
+ public String getTarget() { return mTarget; }
179
+ public Boolean getForce() { return mForce; }
180
+ public Integer getSeq() { return mSeq; }
181
+ public Boolean getJs() { return mJs; }
182
+ public String getPath() { return mPath; }
183
+ public Boolean getReload() { return mReload; }
184
+
185
+ public void setEvent(String v) { mEvent = v; }
186
+ public void setTarget(String v) { mTarget = v; }
187
+ public void setForce(Boolean v) { mForce = v; }
188
+ public void setSeq(Integer v) { mSeq = v; }
189
+ public void setJs(Boolean v) { mJs = v; }
190
+ public void setPath(String v) { mPath = v; }
191
+ public void setReload(Boolean v) { mReload = v; }
192
+
193
+ private String toQueryParam(String name, String p) {
194
+ return p != null ? name+"="+p : "";
195
+ }
196
+ private String toQueryParam(String name, Boolean p) {
197
+ return p != null ? name+"="+p.toString() : "";
198
+ }
199
+ private String toQueryParam(String name, Integer p) {
200
+ return p != null ? name+"="+p.toString() : "";
201
+ }
202
+ }
203
+
204
+ /**
205
+ * Contains state info for a golf request. This is what should be passed
206
+ * around rather than the raw request or response.
207
+ */
208
+ public class GolfContext {
209
+
210
+ public HttpServletRequest request = null;
211
+ public HttpServletResponse response = null;
212
+ public GolfParams p = null;
213
+ public GolfSession s = null;
214
+ public String servletUrl = null;
215
+ public String urlHash = null;
216
+ public BrowserVersion browser = BrowserVersion.FIREFOX_2;
217
+ public StoredJSVM jsvm = null;
218
+ public Boolean logging = true;
219
+
220
+ /**
221
+ * Constructor.
222
+ *
223
+ * FIXME implement this as a singleton
224
+ *
225
+ * @param request the http request object
226
+ * @param response the http response object
227
+ */
228
+ public GolfContext(HttpServletRequest request,
229
+ HttpServletResponse response) {
230
+ this.request = request;
231
+ this.response = response;
232
+ this.p = new GolfParams(request);
233
+ this.s = new GolfSession(request);
234
+ this.servletUrl =
235
+ request
236
+ .getRequestURL()
237
+ .toString()
238
+ .replaceFirst(";jsessionid=.*$", "")
239
+ .replaceFirst(
240
+ "^(https?://[^/]+"+Pattern.quote(request.getContextPath())+").*$",
241
+ "$1"
242
+ );
243
+ this.urlHash =
244
+ request
245
+ .getRequestURL()
246
+ .toString()
247
+ .replaceFirst(";jsessionid=.*$", "")
248
+ .replaceFirst(
249
+ "^https?://[^/]+"+Pattern.quote(request.getContextPath()),
250
+ ""
251
+ );
252
+ }
253
+
254
+ public void init() throws ServletException, RedirectException {
255
+ // some servlet containers have been known to produce a null urlHash
256
+ urlHash = (urlHash == null ? "" : urlHash);
257
+
258
+ // reload the page in proxy mode => destroy old jsvm
259
+ if (p.getReload() != null && p.getReload().booleanValue()) {
260
+ log(this, LOG_INFO, "RELOAD via query parameter");
261
+ mJsvms.remove(request.getSession().getId());
262
+ request.getSession(true).invalidate();
263
+ this.s = new GolfSession(request);
264
+ }
265
+
266
+ // ensure that the URL is in the standard form
267
+
268
+ // http://example.com/app//some/path/ ==>>
269
+ // servletUrl => http://example.com/app
270
+ // urlHash => //some/path/
271
+
272
+ if (urlHash.startsWith("/")) {
273
+ servletUrl = servletUrl + "/";
274
+ urlHash = urlHash.replaceFirst("^/", "");
275
+ } else {
276
+ //System.err.println("{{{ REDIRECT 0 }}}");
277
+ throw new PermanentRedirectException(
278
+ response.encodeRedirectURL(servletUrl+"/"+urlHash));
279
+ }
280
+
281
+ // fetch the jsvm for this guy
282
+ jsvm = mJsvms.get(request.getSession().getId());
283
+
284
+ if (jsvm == null)
285
+ jsvm = new StoredJSVM((WebClient) null);
286
+ }
287
+
288
+ public boolean hasEvent() {
289
+ return (this.p.getEvent() != null && this.p.getTarget() != null);
290
+ }
291
+ }
292
+
293
+ private static ConcurrentHashMap<String, StoredJSVM> mJsvms =
294
+ new ConcurrentHashMap<String, StoredJSVM>();
295
+
296
+ private static int mLogLevel = LOG_ALL;
297
+ private static String mNewHtml = null;
298
+ private static String mNewHtmlFc = null;
299
+ private static String mErrorPage = null;
300
+ private static String mJsDetect = null;
301
+ private static String mDevMode = null;
302
+ private static String mPoolSize = null;
303
+ private static String mPoolExpire = null;
304
+ private static String mAppVersion = null;
305
+ private static AtomicBoolean mBotMutex = new AtomicBoolean();
306
+ private static ArrayList<String> mForceProxy = new ArrayList<String>();
307
+ private static ArrayList<String> mForceClient = new ArrayList<String>();
308
+ private static ArrayList<String> mForceBot = new ArrayList<String>();
309
+
310
+ /**
311
+ * @see javax.servlet.Servlet#init(javax.servlet.ServletConfig)
312
+ */
313
+ public void init(ServletConfig config) throws ServletException {
314
+ super.init(config); // tricky little guy
315
+
316
+ // init parameters
317
+ mDevMode = config.getInitParameter("devmode");
318
+ mPoolSize = config.getInitParameter("poolsize");
319
+ mPoolExpire = config.getInitParameter("poolexpire");
320
+ mAppVersion = config.getInitParameter("version");
321
+
322
+ // default values
323
+ mDevMode = (mDevMode != null ? mDevMode : "true" );
324
+ mPoolSize = (mPoolSize != null ? mPoolSize : "10" );
325
+ mPoolExpire = (mPoolExpire != null ? mPoolExpire : "900" ); // 15 min
326
+
327
+ // set initial values
328
+ mBotMutex.set(false);
329
+
330
+ // process the static files that need to be kept in memory
331
+ cacheStaticFiles();
332
+ }
333
+
334
+ /**
335
+ * Serve http requests!
336
+ *
337
+ * @param request the http request object
338
+ * @param response the http response object
339
+ */
340
+ public void service(HttpServletRequest request, HttpServletResponse response)
341
+ throws IOException, ServletException {
342
+ GolfContext context = null;
343
+ String result = null;
344
+
345
+ // All query string parameters are considered to be arguments directed
346
+ // to the golf container. The app itself gets its arguments in the path
347
+ // info.
348
+
349
+ try {
350
+ // create the context object for this request
351
+ context = new GolfContext(request, response);
352
+
353
+ // log the incoming request before any manipulation is done
354
+ logRequest(context);
355
+
356
+ // initialize context
357
+ context.init();
358
+
359
+ /*
360
+ String url = context.request.getRequestURL().toString()
361
+ .replaceFirst(";jsessionid=.*$", "");
362
+
363
+ if (! url.endsWith("/")) {
364
+ //System.err.println("{{{ REDIRECT 7 }}}");
365
+ throw new PermanentRedirectException(
366
+ context.response.encodeRedirectURL(url + "/"));
367
+ }
368
+ */
369
+
370
+ // handle your business
371
+ if (context.p.getPath() != null)
372
+ doStaticResourceGet(context);
373
+ else
374
+ doDynamicResourceGet(context);
375
+ }
376
+
377
+ catch (PermanentRedirectException r) {
378
+ // 301 PERMANENTLY MOVED
379
+ logResponse(context, 301);
380
+ log(context, LOG_INFO, "301 ---to--> "+r.getMessage());
381
+ context.response.setHeader("Location", r.getMessage());
382
+ context.response.sendError(301);
383
+ }
384
+
385
+ catch (RedirectException r) {
386
+ // 302 FOUND
387
+ logResponse(context, 302);
388
+ log(context, LOG_INFO, "302 ---to--> "+r.getMessage());
389
+ context.response.sendRedirect(r.getMessage());
390
+ }
391
+
392
+ catch (FileNotFoundException e) {
393
+ // 404 NOT FOUND
394
+ logResponse(context, 404);
395
+ errorPage(context, HttpServletResponse.SC_NOT_FOUND, e);
396
+ }
397
+
398
+ catch (Exception x) {
399
+ // 500 INTERNAL SERVER ERROR
400
+ logResponse(context, 500);
401
+ x.printStackTrace();
402
+ errorPage(context, HttpServletResponse.SC_INTERNAL_SERVER_ERROR, x);
403
+ }
404
+ }
405
+
406
+ /**
407
+ * (Re)build static files and cache them in memory
408
+ */
409
+ public void cacheStaticFiles() throws ServletException {
410
+ try {
411
+ if (Boolean.parseBoolean(mDevMode)) {
412
+ Main.cacheComponentsFile();
413
+ Main.cacheNewDotHtmlFile();
414
+ }
415
+ mNewHtml =
416
+ (new GolfResource(getServletContext(), Main.NEW_HTML)).toString();
417
+ mNewHtmlFc =
418
+ (new GolfResource(getServletContext(), Main.NEW_FC_HTML)).toString();
419
+ mErrorPage =
420
+ (new GolfResource(getServletContext(), Main.ERROR_HTML)).toString();
421
+ mJsDetect =
422
+ (new GolfResource(getServletContext(), Main.JSDETECT_HTML)).toString();
423
+
424
+ try {
425
+ // wait for resource to be available
426
+ while (!mBotMutex.compareAndSet(false, true));
427
+
428
+ mForceProxy =
429
+ (new GolfResource(getServletContext(), Main.FORCEPROXY_TXT))
430
+ .toArrayList();
431
+
432
+ mForceClient =
433
+ (new GolfResource(getServletContext(), Main.FORCECLIENT_TXT))
434
+ .toArrayList();
435
+
436
+ mForceBot =
437
+ (new GolfResource(getServletContext(), Main.FORCEBOT_TXT))
438
+ .toArrayList();
439
+
440
+ } catch (FileNotFoundException fx) {
441
+ } finally {
442
+ mBotMutex.set(false);
443
+ }
444
+ } catch (Exception e) {
445
+ throw new ServletException("can't cache static files", e);
446
+ }
447
+ }
448
+
449
+ /**
450
+ * Do text processing of html to inject server/client specific things, etc.
451
+ *
452
+ * @param page the html page contents
453
+ * @param context the golf request object
454
+ * @param server whether to process for serverside or clientside
455
+ * @return the processed page html contents
456
+ */
457
+ private static String preprocess(String page, GolfContext context, boolean server) {
458
+ String sid = context.request.getSession().getId();
459
+
460
+ // pattern matching all script tags (should this be removed?)
461
+ String pat1 = "<noscript>.*</noscript>";
462
+
463
+ // pattern matching all script tags (should this be removed?)
464
+ String pat2 =
465
+ "<script type=\"text/javascript\"[^>]*>([^<]|//<!\\[CDATA\\[)*</script>";
466
+
467
+ // document type: xhtml
468
+ String dtd =
469
+ "<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.0 Strict//EN\"\n" +
470
+ "\"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd\">\n";
471
+
472
+ // remove xml tag (why is it even there?)
473
+ if (!server)
474
+ page = page.replaceFirst("^<\\?xml [^>]+>\n", "");
475
+
476
+ // robots must not index event proxy (because infinite loops, etc.)
477
+ if (!context.hasEvent())
478
+ page = page.replaceFirst("noindex,nofollow", "index,follow");
479
+
480
+ // remove the golfid attribute as it's not necessary on the client
481
+ // and it is frowned upon by the w3c validator
482
+ if (!server)
483
+ page = page.replaceAll("(<[^>]+) golfid=\"[0-9]+\"", "$1");
484
+
485
+ if (! context.s.getJs().booleanValue() && !server) {
486
+ // proxy mode: remove javascript/noscript except for serverside
487
+ page = page.replaceAll(pat1, "");
488
+ page = page.replaceAll(pat2, "");
489
+
490
+ for (int i=0, j=0; (i=page.indexOf("<style", i)) != -1; i=j) {
491
+ j = page.indexOf("</style>", i);
492
+ page = page.substring(0, i)
493
+ + page.substring(i, j).replaceAll("&gt;", ">")
494
+ .replaceAll("&lt;", "<")
495
+ .replaceAll("&amp;", "&")
496
+ .replaceAll("&apos;", "'")
497
+ .replaceAll("\n", "") // FIXME this is sketchy
498
+ + page.substring(j);
499
+ }
500
+
501
+ if (context.s.getForceBot().booleanValue()) {
502
+ page = page.replaceAll("(<[^>]+) style=\"[^\"]*\"", "$1");
503
+ page = page.replaceAll("(<[^>]+) style='[^']*'", "$1");
504
+ page = page.replaceAll("(<[^>]+) class=\"[^\"]*\"", "$1");
505
+ page = page.replaceAll("(<[^>]+) class='[^']*'", "$1");
506
+ }
507
+ } else {
508
+ // on the client window.serverside must be false, and vice versa
509
+ page = page.replaceFirst("__SVRSIDE__", (server ? "true" : "false"));
510
+
511
+ // import the session ID into the javascript environment
512
+ page = page.replaceFirst("__SESSID__", sid);
513
+
514
+ // the servlet url (shenanigans here)
515
+ page = page.replaceFirst("__SERVLET_URL__", context.servletUrl);
516
+
517
+ // the url fragment (shenanigans here)
518
+ page = page.replaceFirst("__URL_HASH__", context.urlHash);
519
+
520
+ // bot mode forced?
521
+ page = page.replaceFirst("__FORCEBOT__",
522
+ context.s.getForceBot().toString());
523
+
524
+ // proxy mode forced?
525
+ page = page.replaceFirst("__FORCEPROXY__",
526
+ context.s.getForceProxy().toString());
527
+
528
+ // client mode forced?
529
+ page = page.replaceFirst("__FORCECLIENT__",
530
+ context.s.getForceClient().toString());
531
+
532
+ // the golf version
533
+ page = page.replaceFirst("__GOLF_VERSION__", mAppVersion);
534
+ }
535
+
536
+ // no dtd for serverside because it breaks the xml parser
537
+ return (server ? "" : dtd) + page;
538
+ }
539
+
540
+ /**
541
+ * Show error page.
542
+ *
543
+ * @param context the golf request context
544
+ * @param e the exception
545
+ */
546
+ public void errorPage(GolfContext context, int status, Exception e) {
547
+ try {
548
+ PrintWriter out = context.response.getWriter();
549
+
550
+ String errHtml =
551
+ mErrorPage.replaceAll("<%error%>", HTMLEntityEncode(e.getMessage()));
552
+
553
+ context.response.setStatus(status);
554
+ context.response.setContentType("text/html");
555
+
556
+ out.print(errHtml);
557
+ } catch (Exception x) {
558
+ x.printStackTrace();
559
+ }
560
+ }
561
+
562
+ /**
563
+ * Send a proxied response.
564
+ *
565
+ * @param context the golf context for this request
566
+ */
567
+ private void doProxy(GolfContext context) throws FileNotFoundException,
568
+ IOException, URISyntaxException, RedirectException, ServletException {
569
+ String sid = context.request.getSession().getId();
570
+ HtmlPage result = context.jsvm.lastPage;
571
+
572
+ String path = context.urlHash;
573
+ String event = context.p.getEvent();
574
+ String target = context.p.getTarget();
575
+ WebClient client = context.jsvm.client;
576
+
577
+ String lastEvent = context.s.getLastEvent();
578
+ String lastTarget = context.s.getLastTarget();
579
+ String lastUrl = context.s.getLastUrl();
580
+
581
+ context.jsvm.lastPage = null;
582
+ context.s.setLastEvent(null);
583
+ context.s.setLastTarget(null);
584
+ context.s.setLastUrl(null);
585
+
586
+ if (result == null || !path.equals(lastUrl)) {
587
+ if (lastEvent == null || lastTarget == null || !path.equals(lastUrl)) {
588
+ if (event != null && target != null && client != null) {
589
+
590
+ // update last access time
591
+ context.jsvm.lastAccessTime = (new Date()).getTime();
592
+
593
+ if (event.equals("onclick")) {
594
+ // nothing here
595
+ } else if (event.equals("onsubmit")) {
596
+ Map<String, String[]> pmap = context.request.getParameterMap();
597
+ for (String key : pmap.keySet()) {
598
+ String val = pmap.get(key)[0].replaceAll("[\"]", "\\x22");
599
+
600
+ String script = "jQuery(\"[name='"+key+"']\").val(\""+val+"\");";
601
+
602
+ result = (HtmlPage) client.getCurrentWindow().getEnclosedPage();
603
+ result.executeJavaScript(script);
604
+ }
605
+ } else {
606
+ throw new ServletException("unsupported event for proxy: "+event);
607
+ }
608
+ context.s.setLastEvent(event);
609
+ context.s.setLastTarget(target);
610
+ context.s.setLastUrl(path);
611
+ if (context.request.getQueryString() != null) {
612
+ //System.err.println("{{{ REDIRECT 1 }}}");
613
+ throw new RedirectException(proxyURLEncode(
614
+ context.response.encodeRedirectURL(context.servletUrl + path)));
615
+ } else {
616
+ lastEvent = context.s.getLastEvent();
617
+ lastTarget = context.s.getLastTarget();
618
+ lastUrl = context.s.getLastUrl();
619
+ }
620
+ } else if (client == null) {
621
+ log(context, LOG_INFO, "*** INITIALIZING NEW CLIENT ***");
622
+ log(context, LOG_INFO, "Running JSVMs, before GC: " + mJsvms.size());
623
+
624
+ createNewJsvm(context);
625
+
626
+ log(context, LOG_INFO, "Running JSVMs, after GC: " + mJsvms.size());
627
+
628
+ client = context.jsvm.client;
629
+
630
+ // write any alert() calls to the log
631
+ client.setAlertHandler(new AlertHandler() {
632
+ public void handleAlert(Page page, String message) {
633
+ System.err.println("ALERT: " + message);
634
+ }
635
+ });
636
+
637
+ // if this isn't long enough it'll timeout before all ajax is complete
638
+ client.setJavaScriptTimeout(JSVM_TIMEOUT);
639
+
640
+ // the blank skeleton html template
641
+ String newHtml = mNewHtml;
642
+
643
+ // do not pass query string to the app, as those parameters are meant
644
+ // only for the golf container itself.
645
+
646
+ StringWebResponse response = new StringWebResponse(
647
+ preprocess(newHtml, context, true),
648
+ new URL(context.servletUrl + "#" + context.urlHash)
649
+ );
650
+
651
+ // run it through htmlunit
652
+ result = (HtmlPage) context.jsvm.client.loadWebResponseInto(
653
+ response,
654
+ client.getCurrentWindow()
655
+ );
656
+ } else {
657
+ String script = "jQuery.address.value('"+context.urlHash+"');";
658
+ result = (HtmlPage) client.getCurrentWindow().getEnclosedPage();
659
+ result.executeJavaScript(script);
660
+ }
661
+ }
662
+
663
+ if (lastEvent != null && lastTarget != null && path.equals(lastUrl)) {
664
+ if (client != null) {
665
+ String script;
666
+ if (lastEvent.equals("onclick")) {
667
+ script = "jQuery(\"[golfid='"+lastTarget+"']\").click()";
668
+ } else if (lastEvent.equals("onsubmit")) {
669
+ script = "jQuery(\"[golfid='"+lastTarget+"']\").submit()";
670
+ } else {
671
+ //System.err.println("{{{ REDIRECT 2 }}}");
672
+ throw new RedirectException(proxyURLEncode(
673
+ context.response.encodeRedirectURL(context.servletUrl + path)));
674
+ }
675
+ result = (HtmlPage) client.getCurrentWindow().getEnclosedPage();
676
+ result.executeJavaScript(script);
677
+ } else {
678
+ //System.err.println("{{{ REDIRECT 3 }}}");
679
+ throw new RedirectException(proxyURLEncode(
680
+ context.response.encodeRedirectURL(context.servletUrl + path)));
681
+ }
682
+ }
683
+
684
+ String loc = (String) result.executeJavaScript(
685
+ "window.location.href").getJavaScriptResult();
686
+
687
+ if (!loc.startsWith(context.servletUrl)) {
688
+ //System.err.println("{{{ REDIRECT 4 }}}");
689
+ throw new RedirectException(
690
+ proxyURLEncode(context.response.encodeRedirectURL(loc)));
691
+ } else {
692
+ loc = loc.replaceFirst("^[^#]+#", "");
693
+ }
694
+
695
+ if (!loc.equals(path) || context.request.getQueryString() != null) {
696
+ context.jsvm.lastPage = result;
697
+ context.s.setLastUrl(loc);
698
+ //System.err.println("{{{ REDIRECT 5 }}}");
699
+ throw new RedirectException(proxyURLEncode(
700
+ context.response.encodeRedirectURL(context.servletUrl + loc)));
701
+ }
702
+ }
703
+
704
+ Iterator<HtmlAnchor> anchors = result.getAnchors().iterator();
705
+ while (anchors.hasNext()) {
706
+ HtmlAnchor a = anchors.next();
707
+ a.setAttribute("href",context.response.encodeURL(a.getHrefAttribute()));
708
+ }
709
+
710
+ result.executeJavaScript(
711
+ "jQuery('.component').each( " +
712
+ "function() { "+
713
+ "var elem = jQuery(this).children().eq(0); "+
714
+ "if (elem) { "+
715
+ "jQuery.golf.jss(elem, true); "+
716
+ "} "+
717
+ "} "+
718
+ ")"
719
+ );
720
+
721
+ String html = preprocess(result.asXml(), context, false);
722
+ sendResponse(context, html, "text/html", false);
723
+ }
724
+
725
+ /**
726
+ * Send a non-proxied response.
727
+ *
728
+ * @param context the golf context for this request
729
+ */
730
+ private void doNoProxy(GolfContext context) throws Exception {
731
+ // the blank skeleton html template
732
+ String html = (context.s.getForceClient() ? mNewHtmlFc : mNewHtml);
733
+ sendResponse(context, preprocess(html, context, false), "text/html", true);
734
+ }
735
+
736
+ /**
737
+ * First clean out any old JSVMs that might be hanging around, then
738
+ * make sure there is room for another jsvm.
739
+ */
740
+ private void createNewJsvm(GolfContext context) throws ServletException {
741
+ int psize = Integer.parseInt(mPoolSize);
742
+ long ptime = Long.parseLong(mPoolExpire) * 1000L; // convert sec --> msec
743
+ long ctime = (new Date()).getTime();
744
+
745
+ for (String key : mJsvms.keySet())
746
+ if (ctime - mJsvms.get(key).lastAccessTime > ptime)
747
+ mJsvms.remove(key);
748
+
749
+ if (mJsvms.size() >= psize) {
750
+ throw new ServletException(
751
+ "The server has too many concurrent proxy sessions right now. "+
752
+ "Please enable javascript in your browser (if you can) or try "+
753
+ "again later."
754
+ );
755
+ }
756
+
757
+ context.jsvm.client = new WebClient(context.browser);
758
+ mJsvms.put(context.request.getSession().getId(), context.jsvm);
759
+ }
760
+
761
+ /**
762
+ * Do the dynamic request.
763
+ *
764
+ * @param context the golf context for this request
765
+ */
766
+ private void doDynamicResourceGet(GolfContext context) throws Exception {
767
+
768
+ HttpSession session = context.request.getSession();
769
+ String remoteAddr = context.request.getRemoteAddr();
770
+ String sessionAddr = context.s.getIpAddr();
771
+ Boolean forcebot = context.s.getForceBot();
772
+ Boolean forceproxy = context.s.getForceProxy();
773
+ Boolean forceclient = context.s.getForceClient();
774
+ Boolean forceParam = context.p.getForce();
775
+ Boolean jsParam = context.p.getJs();
776
+ String sid = session.getId();
777
+ String uagent = context.request.getHeader("User-Agent");
778
+
779
+ if (sid == null)
780
+ throw new Exception("sid is null");
781
+
782
+ if (Boolean.parseBoolean(mDevMode)) {
783
+ cacheStaticFiles();
784
+ context.s.setForceProxy(forceproxy = null);
785
+ context.s.setForceClient(forceclient = null);
786
+ }
787
+
788
+ // forcebot: Match regex to user agent string.
789
+ // If match, treat user agent as a bot (no css,
790
+ // no presentation cruft, cleaner markup).
791
+
792
+ // FIXME: store this info in session unless in devmode, maybe
793
+ if (forcebot == null) {
794
+ forcebot = multipatternMatch(uagent, mForceBot);
795
+ context.s.setForceBot(forcebot);
796
+ }
797
+
798
+ // forceproxy: Match regex to user agent string.
799
+ // If match, force proxy mode immediately. Forcebot
800
+ // implies forceproxy.
801
+
802
+ // FIXME: store this info in session unless in devmode, maybe
803
+ if (forceproxy == null) {
804
+ if (forceproxy =
805
+ (multipatternMatch(uagent, mForceProxy) || forcebot)) {
806
+ context.s.setJs(false);
807
+ context.s.setSeq(1);
808
+ }
809
+ context.s.setForceProxy(forceproxy);
810
+ }
811
+
812
+ // forceclient: Match regex to user agent string.
813
+ // If match, force client mode immediately, unless
814
+ // forceproxy is set (forceproxy has higher precedence).
815
+
816
+ // FIXME: store this info in session unless in devmode, maybe
817
+ if (forceclient == null) {
818
+ forceclient = false;
819
+ if (forceproxy == false) {
820
+ if (forceclient = multipatternMatch(uagent, mForceClient)) {
821
+ context.s.setJs(true);
822
+ context.s.setSeq(1);
823
+ }
824
+ }
825
+ context.s.setForceClient(forceclient);
826
+ }
827
+
828
+ Boolean forceUa = forceproxy || forceclient;
829
+
830
+ if (! session.isNew() || forceUa) {
831
+ if (!forceUa && forceParam != null && forceParam.booleanValue())
832
+ context.s.setSeq(0);
833
+
834
+ int seq = (context.s.getSeq() == null ? 0 : (int) context.s.getSeq());
835
+
836
+ context.s.setSeq(++seq);
837
+
838
+ if (forceUa || sessionAddr != null && sessionAddr.equals(remoteAddr)) {
839
+ if (!forceUa && seq == 1) {
840
+ if (jsParam != null) {
841
+ String uri;
842
+ boolean js = jsParam.booleanValue();
843
+
844
+ context.s.setJs(js);
845
+
846
+ if (js) {
847
+ uri = context.servletUrl +
848
+ (context.urlHash.length() > 0 ? "#" + context.urlHash : "");
849
+ } else {
850
+ uri = context.request.getRequestURL().toString();
851
+ }
852
+
853
+ //System.err.println("{{{ REDIRECT 6 }}}");
854
+ throw new RedirectException(
855
+ context.response.encodeRedirectURL(uri));
856
+ }
857
+ } else if (forceUa || seq >= 2) {
858
+ if (forceUa || context.s.getJs() != null) {
859
+ // FIXME: lurking NPE if you change this
860
+ if (forceclient ||
861
+ (!forceproxy && context.s.getJs().booleanValue()))
862
+ doNoProxy(context);
863
+ else
864
+ doProxy(context);
865
+ return;
866
+ }
867
+ }
868
+ }
869
+
870
+ session.invalidate();
871
+ context.s = new GolfSession(context.request);
872
+ }
873
+
874
+ context.s.setSeq(new Integer(0));
875
+ context.s.setIpAddr(remoteAddr);
876
+
877
+ String jsDetect = mJsDetect;
878
+
879
+ jsDetect =
880
+ jsDetect.replaceAll("__HAVE_JS__", ";jsessionid="+sid+"?js=true");
881
+ jsDetect =
882
+ jsDetect.replaceAll("__DONT_HAVE_JS__", ";jsessionid="+sid+"?js=false");
883
+
884
+ sendResponse(context, jsDetect, "text/html", false);
885
+ }
886
+
887
+ private boolean multipatternMatch(String ua, ArrayList<String> pats) {
888
+ for (String i : pats)
889
+ if (ua.matches(i))
890
+ return true;
891
+ return false;
892
+ }
893
+
894
+ private void sendResponse(GolfContext context, String html,
895
+ String contentType, boolean canCache) throws IOException {
896
+ context.response.setContentType(contentType);
897
+
898
+ if (canCache)
899
+ setCachable(context);
900
+
901
+ PrintWriter out = context.response.getWriter();
902
+ out.print(html);
903
+ out.close();
904
+ logResponse(context, 200);
905
+ }
906
+
907
+ private void setCachable(GolfContext context) {
908
+ long currentTime = System.currentTimeMillis();
909
+ long later = 24*60*60*1000; // a day (milliseconds)
910
+ context.response.setDateHeader("Expires", currentTime + later);
911
+ context.response.setHeader("Cache-Control", "max-age=3600,public");
912
+ }
913
+
914
+ /**
915
+ * Handle a request for a static resource.
916
+ *
917
+ * @param context the golf context for this request
918
+ */
919
+ private void doStaticResourceGet(GolfContext context)
920
+ throws FileNotFoundException, IOException, JSONException {
921
+ String path = context.p.getPath();
922
+
923
+ if (path.matches("^[/]*\\."))
924
+ throw new FileNotFoundException();
925
+
926
+ if (! path.startsWith("/"))
927
+ path = "/" + path;
928
+
929
+ GolfResource res = new GolfResource(getServletContext(), path);
930
+
931
+ context.response.setContentType(res.getMimeType());
932
+ setCachable(context);
933
+
934
+ if (res.getMimeType().startsWith("text/")) {
935
+ PrintWriter out = context.response.getWriter();
936
+ out.print(res.toString());
937
+ } else {
938
+ OutputStream out = context.response.getOutputStream();
939
+ out.write(res.toByteArray());
940
+ }
941
+
942
+ logResponse(context, 200);
943
+ }
944
+
945
+ /**
946
+ * Format a nice log message.
947
+ *
948
+ * @param context the golf context for this request
949
+ * @param s the log message
950
+ * @return the formatted log message
951
+ */
952
+ private String fmt(GolfContext context, String s) {
953
+ String sid = null;
954
+ String ip = null;
955
+
956
+ if (context != null) {
957
+ sid = context.request.getSession().getId();
958
+ ip = context.request.getRemoteHost();
959
+ }
960
+
961
+ sid = sid != null ? "[" + sid.toUpperCase().replaceAll(
962
+ "(...)(?=...)", "$1.") + "] " : "";
963
+ ip = ip != null ? ip+"\n >>> " : "";
964
+
965
+ return sid + ip + s;
966
+ }
967
+
968
+ /**
969
+ * Send a formatted message to the logs.
970
+ *
971
+ * @param context the golf context for this request
972
+ * @param level the severity of the message (LOG_TRACE to LOG_FATAL)
973
+ * @param s the log message
974
+ */
975
+ public void log(GolfContext context, int level, String s) {
976
+ ServletContext c = getServletContext();
977
+ if (context.logging && mLogLevel <= level)
978
+ c.log(fmt(context, s));
979
+ }
980
+
981
+ /**
982
+ * Logs a http servlet request.
983
+ *
984
+ * @param context the golf context for this request
985
+ */
986
+ private void logRequest(GolfContext context) {
987
+ String method = context.request.getMethod();
988
+ String path = context.urlHash;
989
+ String query = context.request.getQueryString();
990
+ String host = context.request.getRemoteHost();
991
+ String sid = context.request.getSession().getId();
992
+ String uagent = context.request.getHeader("User-Agent");
993
+
994
+ String line = method + " " + path + (query != null ? "?" + query : "");
995
+
996
+ log(context, LOG_INFO, line);
997
+ log(context, LOG_INFO, uagent);
998
+
999
+ //System.out.println("||||||||||||||||||||||||||||||||||||||");
1000
+ //Enumeration headerNames = context.request.getHeaderNames();
1001
+ //while(headerNames.hasMoreElements()) {
1002
+ // String headerName = (String)headerNames.nextElement();
1003
+ // System.out.println("||||||||||| " + headerName + ": "
1004
+ // + context.request.getHeader(headerName));
1005
+ //}
1006
+ //System.out.println("||||||||||||||||||||||||||||||||||||||");
1007
+
1008
+ }
1009
+
1010
+ /**
1011
+ * Logs a http servlet response.
1012
+ *
1013
+ * @param context the golf context for this request
1014
+ */
1015
+ private void logResponse(GolfContext context, int status) {
1016
+ String method = String.valueOf(status);
1017
+ String path = context.urlHash;
1018
+ String query = context.request.getQueryString();
1019
+ String host = context.request.getRemoteHost();
1020
+ String sid = context.request.getSession().getId();
1021
+
1022
+ String line = method + " " + path + (query != null ? "?" + query : "");
1023
+
1024
+ log(context, LOG_INFO, line);
1025
+ }
1026
+
1027
+ /**
1028
+ * Convenience function to do html entity encoding.
1029
+ *
1030
+ * @param s the string to encode
1031
+ * @return the encoded string
1032
+ */
1033
+ public static String HTMLEntityEncode(String s) {
1034
+ StringBuffer buf = new StringBuffer();
1035
+ int len = (s == null ? -1 : s.length());
1036
+
1037
+ for ( int i = 0; i < len; i++ ) {
1038
+ char c = s.charAt( i );
1039
+ if ( c>='a' && c<='z' || c>='A' && c<='Z' || c>='0' && c<='9' ) {
1040
+ buf.append( c );
1041
+ } else {
1042
+ buf.append("&#" + (int)c + ";");
1043
+ }
1044
+ }
1045
+
1046
+ return buf.toString();
1047
+ }
1048
+
1049
+ /**
1050
+ *
1051
+ */
1052
+ public static String proxyURLEncode(String s) {
1053
+ return s.replaceAll("#", "%23");
1054
+ }
1055
+ }