golf 0.0.1 → 0.0.2

Sign up to get free protection for your applications and to get access to all the features.
Files changed (123) hide show
  1. data/golf.gemspec +1 -1
  2. data/lib/golf/version.rb +1 -1
  3. metadata +1 -121
  4. data/golf-java/README.markdown +0 -41
  5. data/golf-java/THANKS.markdown +0 -14
  6. data/golf-java/build/classes.zip +0 -0
  7. data/golf-java/build/com/thinkminimo/golf/GolfResource$MimeMapping$MimeMappingSingleton.class +0 -0
  8. data/golf-java/build/com/thinkminimo/golf/GolfResource$MimeMapping.class +0 -0
  9. data/golf-java/build/com/thinkminimo/golf/GolfResource.class +0 -0
  10. data/golf-java/build/com/thinkminimo/golf/GolfServlet$1.class +0 -0
  11. data/golf-java/build/com/thinkminimo/golf/GolfServlet$GolfContext.class +0 -0
  12. data/golf-java/build/com/thinkminimo/golf/GolfServlet$GolfParams.class +0 -0
  13. data/golf-java/build/com/thinkminimo/golf/GolfServlet$GolfSession.class +0 -0
  14. data/golf-java/build/com/thinkminimo/golf/GolfServlet$PermanentRedirectException.class +0 -0
  15. data/golf-java/build/com/thinkminimo/golf/GolfServlet$RedirectException.class +0 -0
  16. data/golf-java/build/com/thinkminimo/golf/GolfServlet$StoredJSVM.class +0 -0
  17. data/golf-java/build/com/thinkminimo/golf/GolfServlet.class +0 -0
  18. data/golf-java/build/com/thinkminimo/golf/JsonpTunnel.class +0 -0
  19. data/golf-java/build/com/thinkminimo/golf/Main$1.class +0 -0
  20. data/golf-java/build/com/thinkminimo/golf/Main$RingList.class +0 -0
  21. data/golf-java/build/com/thinkminimo/golf/Main.class +0 -0
  22. data/golf-java/build/com/thinkminimo/golf/ProxyServlet.class +0 -0
  23. data/golf-java/build/com/yahoo/platform/yui/compressor/CssCompressor.class +0 -0
  24. data/golf-java/build/com/yahoo/platform/yui/compressor/JarClassLoader.class +0 -0
  25. data/golf-java/build/com/yahoo/platform/yui/compressor/JavaScriptCompressor.class +0 -0
  26. data/golf-java/build/com/yahoo/platform/yui/compressor/JavaScriptIdentifier.class +0 -0
  27. data/golf-java/build/com/yahoo/platform/yui/compressor/JavaScriptToken.class +0 -0
  28. data/golf-java/build/com/yahoo/platform/yui/compressor/ScriptOrFnScope.class +0 -0
  29. data/golf-java/build/depends.zip +0 -0
  30. data/golf-java/build/golf +0 -2
  31. data/golf-java/build/org/json/JSONArray.class +0 -0
  32. data/golf-java/build/org/json/JSONException.class +0 -0
  33. data/golf-java/build/org/json/JSONObject$1.class +0 -0
  34. data/golf-java/build/org/json/JSONObject$Null.class +0 -0
  35. data/golf-java/build/org/json/JSONObject.class +0 -0
  36. data/golf-java/build/org/json/JSONString.class +0 -0
  37. data/golf-java/build/org/json/JSONStringer.class +0 -0
  38. data/golf-java/build/org/json/JSONTokener.class +0 -0
  39. data/golf-java/build/org/json/JSONWriter.class +0 -0
  40. data/golf-java/build/resources.zip +0 -0
  41. data/golf-java/build.xml +0 -174
  42. data/golf-java/dist/golf.zip +0 -0
  43. data/golf-java/lib/ant-launcher.jar +0 -0
  44. data/golf-java/lib/ant.jar +0 -0
  45. data/golf-java/lib/commons-codec-1.4.jar +0 -0
  46. data/golf-java/lib/commons-collections-3.2.1.jar +0 -0
  47. data/golf-java/lib/commons-fileupload-1.2.1.jar +0 -0
  48. data/golf-java/lib/commons-httpclient-3.1.jar +0 -0
  49. data/golf-java/lib/commons-io-1.4.jar +0 -0
  50. data/golf-java/lib/commons-lang-2.4.jar +0 -0
  51. data/golf-java/lib/commons-logging-1.1.1.jar +0 -0
  52. data/golf-java/lib/cssparser-0.9.5.jar +0 -0
  53. data/golf-java/lib/getopt-0.1-dev.jar +0 -0
  54. data/golf-java/lib/htmlunit-2.6.jar +0 -0
  55. data/golf-java/lib/htmlunit-core-js-2.6.jar +0 -0
  56. data/golf-java/lib/java-xmlbuilder-1.jar +0 -0
  57. data/golf-java/lib/jets3t-0.7.0.jar +0 -0
  58. data/golf-java/lib/jetty-6.1.15.jar +0 -0
  59. data/golf-java/lib/jetty-util-6.1.15.jar +0 -0
  60. data/golf-java/lib/log4j-1.2.15.jar +0 -0
  61. data/golf-java/lib/nekohtml-1.9.13.jar +0 -0
  62. data/golf-java/lib/sac-1.3.jar +0 -0
  63. data/golf-java/lib/serializer-2.7.1.jar +0 -0
  64. data/golf-java/lib/servlet-api-2.5-20081211.jar +0 -0
  65. data/golf-java/lib/xalan-2.7.1.jar +0 -0
  66. data/golf-java/lib/xercesImpl-2.9.1.jar +0 -0
  67. data/golf-java/lib/xml-apis-1.3.04.jar +0 -0
  68. data/golf-java/resources/app_error.html +0 -60
  69. data/golf-java/resources/error.html +0 -29
  70. data/golf-java/resources/forcebot.txt +0 -0
  71. data/golf-java/resources/forceclient.txt +0 -0
  72. data/golf-java/resources/forceproxy.txt +0 -0
  73. data/golf-java/resources/head.html +0 -0
  74. data/golf-java/resources/jquery.address.js +0 -439
  75. data/golf-java/resources/jquery.golf.js +0 -945
  76. data/golf-java/resources/jquery.js +0 -4376
  77. data/golf-java/resources/jsdetect.html +0 -23
  78. data/golf-java/resources/loading.gif +0 -0
  79. data/golf-java/resources/new.html +0 -45
  80. data/golf-java/resources/new.static.html +0 -45
  81. data/golf-java/resources/noscript.forceclient.html +0 -11
  82. data/golf-java/resources/noscript.html +0 -18
  83. data/golf-java/resources/noscript.static.html +0 -15
  84. data/golf-java/resources/project.xml +0 -21
  85. data/golf-java/resources/proxy_project.xml +0 -11
  86. data/golf-java/resources/proxy_web.xml +0 -40
  87. data/golf-java/resources/static_project.xml +0 -37
  88. data/golf-java/resources/version +0 -1
  89. data/golf-java/resources/web.xml +0 -36
  90. data/golf-java/resources/welcome2golf.html +0 -50
  91. data/golf-java/src/com/thinkminimo/golf/GolfResource.java +0 -582
  92. data/golf-java/src/com/thinkminimo/golf/GolfServlet.java +0 -1055
  93. data/golf-java/src/com/thinkminimo/golf/JsonpTunnel.java +0 -86
  94. data/golf-java/src/com/thinkminimo/golf/Main.java +0 -1299
  95. data/golf-java/src/com/thinkminimo/golf/ProxyServlet.java +0 -577
  96. data/golf-java/src/com/yahoo/platform/yui/compressor/CssCompressor.java +0 -188
  97. data/golf-java/src/com/yahoo/platform/yui/compressor/JarClassLoader.java +0 -158
  98. data/golf-java/src/com/yahoo/platform/yui/compressor/JavaScriptCompressor.java +0 -1281
  99. data/golf-java/src/com/yahoo/platform/yui/compressor/JavaScriptIdentifier.java +0 -55
  100. data/golf-java/src/com/yahoo/platform/yui/compressor/JavaScriptToken.java +0 -28
  101. data/golf-java/src/com/yahoo/platform/yui/compressor/ScriptOrFnScope.java +0 -160
  102. data/golf-java/src/org/json/JSONArray.java +0 -934
  103. data/golf-java/src/org/json/JSONException.java +0 -27
  104. data/golf-java/src/org/json/JSONObject.java +0 -1550
  105. data/golf-java/src/org/json/JSONString.java +0 -18
  106. data/golf-java/src/org/json/JSONStringer.java +0 -78
  107. data/golf-java/src/org/json/JSONTokener.java +0 -422
  108. data/golf-java/src/org/json/JSONWriter.java +0 -323
  109. data/golf-java/test/client/golftest/README.markdown +0 -3
  110. data/golf-java/test/client/golftest/components/com/thinkminimo/golf/test/Harness.css +0 -114
  111. data/golf-java/test/client/golftest/components/com/thinkminimo/golf/test/Harness.html +0 -17
  112. data/golf-java/test/client/golftest/components/com/thinkminimo/golf/test/Harness.js +0 -81
  113. data/golf-java/test/client/golftest/components/com/thinkminimo/golf/test/Harness.res/asc.gif +0 -0
  114. data/golf-java/test/client/golftest/components/com/thinkminimo/golf/test/Harness.res/bg.gif +0 -0
  115. data/golf-java/test/client/golftest/components/com/thinkminimo/golf/test/Harness.res/desc.gif +0 -0
  116. data/golf-java/test/client/golftest/components/com/thinkminimo/golf/test/Harness.res/test/test.html +0 -1
  117. data/golf-java/test/client/golftest/controller.js +0 -131
  118. data/golf-java/test/client/golftest/forceclient.txt +0 -0
  119. data/golf-java/test/client/golftest/forceproxy.txt +0 -0
  120. data/golf-java/test/client/golftest/head.html +0 -1
  121. data/golf-java/test/client/golftest/scripts/jquery.tablesort.js +0 -75
  122. data/golf-java/test/client/golftest/styles/style.css +0 -18
  123. data/golf-java/test/client/golftest/test/test.html +0 -1
@@ -1,1055 +0,0 @@
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
- }