golf 0.0.1 → 0.0.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
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
- }