rsence-pre 2.1.0.1.pre

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 (313) hide show
  1. data/.yardopts +10 -0
  2. data/INSTALL.rdoc +330 -0
  3. data/LICENSE.txt +622 -0
  4. data/README.rdoc +98 -0
  5. data/VERSION +1 -0
  6. data/bin/rsence +25 -0
  7. data/bin/rsence-pre +25 -0
  8. data/conf/default_conf.yaml +346 -0
  9. data/conf/default_strings.yaml +76 -0
  10. data/conf/rsence_command_strings.yaml +444 -0
  11. data/docs/ExampleGuiPlugin.rdoc +193 -0
  12. data/docs/JavascriptBundles.rdoc +0 -0
  13. data/docs/PluginBundleInfo.rdoc +173 -0
  14. data/docs/PluginBundles.rdoc +96 -0
  15. data/docs/Values.rdoc +163 -0
  16. data/js/comm/autosync/autosync.js +17 -0
  17. data/js/comm/autosync/js.inc +0 -0
  18. data/js/comm/comm.js +203 -0
  19. data/js/comm/js.inc +0 -0
  20. data/js/comm/jsloader/js.inc +0 -0
  21. data/js/comm/jsloader/jsloader.js +112 -0
  22. data/js/comm/queue/js.inc +0 -0
  23. data/js/comm/queue/queue.js +184 -0
  24. data/js/comm/session/js.inc +0 -0
  25. data/js/comm/session/session.js +52 -0
  26. data/js/comm/sessionwatcher/js.inc +0 -0
  27. data/js/comm/sessionwatcher/sessionwatcher.js +44 -0
  28. data/js/comm/transporter/js.inc +0 -0
  29. data/js/comm/transporter/transporter.js +261 -0
  30. data/js/comm/urlresponder/js.inc +0 -0
  31. data/js/comm/urlresponder/urlresponder.js +149 -0
  32. data/js/comm/values/js.inc +0 -0
  33. data/js/comm/values/values.js +433 -0
  34. data/js/controls/button/button.js +72 -0
  35. data/js/controls/button/js.inc +0 -0
  36. data/js/controls/button/themes/bright/button.css +89 -0
  37. data/js/controls/button/themes/bright/button.html +7 -0
  38. data/js/controls/button/themes/bright/button_parts1-ie6.gif +0 -0
  39. data/js/controls/button/themes/bright/button_parts1.png +0 -0
  40. data/js/controls/button/themes/default/button.css +89 -0
  41. data/js/controls/button/themes/default/button.html +7 -0
  42. data/js/controls/button/themes/default/button_parts1-ie6.gif +0 -0
  43. data/js/controls/button/themes/default/button_parts1.png +0 -0
  44. data/js/controls/checkbox/checkbox.js +49 -0
  45. data/js/controls/checkbox/js.inc +0 -0
  46. data/js/controls/checkbox/themes/default/checkbox.css +69 -0
  47. data/js/controls/checkbox/themes/default/checkbox.html +5 -0
  48. data/js/controls/checkbox/themes/default/checkbox_parts1-ie6.gif +0 -0
  49. data/js/controls/checkbox/themes/default/checkbox_parts1.png +0 -0
  50. data/js/controls/dialogs/alert_sheet/alert_sheet.js +63 -0
  51. data/js/controls/dialogs/alert_sheet/js.inc +0 -0
  52. data/js/controls/dialogs/confirm_sheet/confirm_sheet.js +37 -0
  53. data/js/controls/dialogs/confirm_sheet/js.inc +0 -0
  54. data/js/controls/dialogs/sheet/js.inc +0 -0
  55. data/js/controls/dialogs/sheet/sheet.js +84 -0
  56. data/js/controls/dialogs/sheet/themes/default/sheet.css +64 -0
  57. data/js/controls/dialogs/sheet/themes/default/sheet.html +14 -0
  58. data/js/controls/dialogs/sheet/themes/default/sheet_bg-ie6.gif +0 -0
  59. data/js/controls/dialogs/sheet/themes/default/sheet_bg.png +0 -0
  60. data/js/controls/dialogs/sheet/themes/default/sheet_dim-ie6.gif +0 -0
  61. data/js/controls/dialogs/sheet/themes/default/sheet_dim.png +0 -0
  62. data/js/controls/dialogs/sheet/themes/default/sheet_parts1-ie6.gif +0 -0
  63. data/js/controls/dialogs/sheet/themes/default/sheet_parts1.png +0 -0
  64. data/js/controls/dialogs/sheet/themes/default/sheet_parts2-ie6.gif +0 -0
  65. data/js/controls/dialogs/sheet/themes/default/sheet_parts2.png +0 -0
  66. data/js/controls/dialogs/sheet/themes/default/sheet_warning-ie6.gif +0 -0
  67. data/js/controls/dialogs/sheet/themes/default/sheet_warning.png +0 -0
  68. data/js/controls/imageview/imageview.js +109 -0
  69. data/js/controls/imageview/js.inc +0 -0
  70. data/js/controls/imageview/themes/default/blank.gif +0 -0
  71. data/js/controls/passwordcontrol/js.inc +0 -0
  72. data/js/controls/passwordcontrol/passwordcontrol.js +23 -0
  73. data/js/controls/passwordcontrol/themes/default/passwordcontrol.css +0 -0
  74. data/js/controls/passwordcontrol/themes/default/passwordcontrol.html +18 -0
  75. data/js/controls/progress/progressbar/js.inc +0 -0
  76. data/js/controls/progress/progressbar/progressbar.js +40 -0
  77. data/js/controls/progress/progressbar/themes/default/progressbar.css +16 -0
  78. data/js/controls/progress/progressbar/themes/default/progressbar.html +2 -0
  79. data/js/controls/progress/progressindicator/js.inc +0 -0
  80. data/js/controls/progress/progressindicator/progressindicator.js +44 -0
  81. data/js/controls/radiobutton/js.inc +0 -0
  82. data/js/controls/radiobutton/radiobutton.js +43 -0
  83. data/js/controls/radiobutton/themes/default/radiobutton.css +69 -0
  84. data/js/controls/radiobutton/themes/default/radiobutton.html +5 -0
  85. data/js/controls/radiobutton/themes/default/radiobutton_parts1-ie6.gif +0 -0
  86. data/js/controls/radiobutton/themes/default/radiobutton_parts1.png +0 -0
  87. data/js/controls/sliders/slider/js.inc +0 -0
  88. data/js/controls/sliders/slider/slider.js +357 -0
  89. data/js/controls/sliders/slider/themes/default/hslider_tracks-ie6.gif +0 -0
  90. data/js/controls/sliders/slider/themes/default/hslider_tracks.png +0 -0
  91. data/js/controls/sliders/slider/themes/default/slider.css +108 -0
  92. data/js/controls/sliders/slider/themes/default/slider.html +5 -0
  93. data/js/controls/sliders/slider/themes/default/slider_thumbs-ie6.gif +0 -0
  94. data/js/controls/sliders/slider/themes/default/slider_thumbs.png +0 -0
  95. data/js/controls/sliders/vslider/js.inc +0 -0
  96. data/js/controls/sliders/vslider/themes/default/vslider.css +52 -0
  97. data/js/controls/sliders/vslider/themes/default/vslider.html +5 -0
  98. data/js/controls/sliders/vslider/themes/default/vslider_tracks-ie6.gif +0 -0
  99. data/js/controls/sliders/vslider/themes/default/vslider_tracks.png +0 -0
  100. data/js/controls/sliders/vslider/vslider.js +41 -0
  101. data/js/controls/stepper/js.inc +0 -0
  102. data/js/controls/stepper/stepper.js +213 -0
  103. data/js/controls/stepper/themes/default/stepper-ie6.gif +0 -0
  104. data/js/controls/stepper/themes/default/stepper.css +14 -0
  105. data/js/controls/stepper/themes/default/stepper.html +2 -0
  106. data/js/controls/stepper/themes/default/stepper.png +0 -0
  107. data/js/controls/stringview/js.inc +0 -0
  108. data/js/controls/stringview/stringview.js +49 -0
  109. data/js/controls/stringview/themes/default/stringview.css +8 -0
  110. data/js/controls/stringview/themes/default/stringview.html +1 -0
  111. data/js/controls/tab/js.inc +0 -0
  112. data/js/controls/tab/tab.js +280 -0
  113. data/js/controls/tab/themes/bright/tab.css +76 -0
  114. data/js/controls/tab/themes/bright/tab.html +6 -0
  115. data/js/controls/tab/themes/bright/tab_bg_color-ie6.gif +0 -0
  116. data/js/controls/tab/themes/bright/tab_bg_color.png +0 -0
  117. data/js/controls/tab/themes/bright/tab_border_pattern-ie6.gif +0 -0
  118. data/js/controls/tab/themes/bright/tab_border_pattern.png +0 -0
  119. data/js/controls/tab/themes/bright/tab_parts1-ie6.gif +0 -0
  120. data/js/controls/tab/themes/bright/tab_parts1.png +0 -0
  121. data/js/controls/tab/themes/default/tab.css +77 -0
  122. data/js/controls/tab/themes/default/tab.html +6 -0
  123. data/js/controls/tab/themes/default/tab_bg_color-ie6.gif +0 -0
  124. data/js/controls/tab/themes/default/tab_bg_color.png +0 -0
  125. data/js/controls/tab/themes/default/tab_border_pattern-ie6.gif +0 -0
  126. data/js/controls/tab/themes/default/tab_border_pattern.png +0 -0
  127. data/js/controls/tab/themes/default/tab_parts1-ie6.gif +0 -0
  128. data/js/controls/tab/themes/default/tab_parts1.png +0 -0
  129. data/js/controls/textarea/js.inc +0 -0
  130. data/js/controls/textarea/textarea.js +24 -0
  131. data/js/controls/textarea/themes/default/textarea.css +21 -0
  132. data/js/controls/textarea/themes/default/textarea.html +18 -0
  133. data/js/controls/textcontrol/js.inc +0 -0
  134. data/js/controls/textcontrol/textcontrol.js +374 -0
  135. data/js/controls/textcontrol/themes/default/textcontrol.css +107 -0
  136. data/js/controls/textcontrol/themes/default/textcontrol.html +18 -0
  137. data/js/controls/textcontrol/themes/default/textcontrol_parts1-ie6.gif +0 -0
  138. data/js/controls/textcontrol/themes/default/textcontrol_parts1.png +0 -0
  139. data/js/controls/textcontrol/themes/default/textcontrol_parts2-ie6.gif +0 -0
  140. data/js/controls/textcontrol/themes/default/textcontrol_parts2.png +0 -0
  141. data/js/controls/textcontrol/themes/default/textcontrol_parts3-ie6.gif +0 -0
  142. data/js/controls/textcontrol/themes/default/textcontrol_parts3.png +0 -0
  143. data/js/controls/uploader/js.inc +0 -0
  144. data/js/controls/uploader/themes/default/upload_progress.gif +0 -0
  145. data/js/controls/uploader/themes/default/uploader.css +108 -0
  146. data/js/controls/uploader/themes/default/uploader.html +27 -0
  147. data/js/controls/uploader/uploader.js +154 -0
  148. data/js/controls/validatorview/js.inc +0 -0
  149. data/js/controls/validatorview/themes/default/validator-ie6.gif +0 -0
  150. data/js/controls/validatorview/themes/default/validator.png +0 -0
  151. data/js/controls/validatorview/themes/default/validatorview.css +0 -0
  152. data/js/controls/validatorview/themes/default/validatorview.html +0 -0
  153. data/js/controls/validatorview/validatorview.js +62 -0
  154. data/js/controls/window/js.inc +0 -0
  155. data/js/controls/window/themes/default/window.css +219 -0
  156. data/js/controls/window/themes/default/window.html +17 -0
  157. data/js/controls/window/themes/default/window_bg_active-ie6.gif +0 -0
  158. data/js/controls/window/themes/default/window_bg_active.png +0 -0
  159. data/js/controls/window/themes/default/window_bg_inactive-ie6.gif +0 -0
  160. data/js/controls/window/themes/default/window_bg_inactive.png +0 -0
  161. data/js/controls/window/themes/default/window_buttons-ie6.gif +0 -0
  162. data/js/controls/window/themes/default/window_buttons.png +0 -0
  163. data/js/controls/window/themes/default/window_parts1-ie6.gif +0 -0
  164. data/js/controls/window/themes/default/window_parts1.png +0 -0
  165. data/js/controls/window/themes/default/window_parts2-ie6.gif +0 -0
  166. data/js/controls/window/themes/default/window_parts2.png +0 -0
  167. data/js/controls/window/window.js +286 -0
  168. data/js/core/class/class.js +318 -0
  169. data/js/core/class/js.inc +0 -0
  170. data/js/core/elem/elem.js +1383 -0
  171. data/js/core/elem/js.inc +0 -0
  172. data/js/core/event/event.js +153 -0
  173. data/js/core/event/js.inc +0 -0
  174. data/js/core/iefix/ie_css_element.htc +5 -0
  175. data/js/core/iefix/ie_css_style.htc +5 -0
  176. data/js/core/iefix/iefix.js +359 -0
  177. data/js/core/iefix/js.inc +0 -0
  178. data/js/core/rsence_ns/js.inc +0 -0
  179. data/js/core/rsence_ns/rsence_ns.js +21 -0
  180. data/js/datetime/calendar/calendar.js +198 -0
  181. data/js/datetime/calendar/js.inc +0 -0
  182. data/js/datetime/calendar/themes/default/calendar.css +108 -0
  183. data/js/datetime/calendar/themes/default/calendar.html +9 -0
  184. data/js/datetime/calendar/themes/default/calendar_arrows-ie6.gif +0 -0
  185. data/js/datetime/calendar/themes/default/calendar_arrows.png +0 -0
  186. data/js/datetime/datetimevalue/datetimevalue.js +247 -0
  187. data/js/datetime/datetimevalue/js.inc +0 -0
  188. data/js/datetime/timesheet/js.inc +0 -0
  189. data/js/datetime/timesheet/themes/default/timesheet.css +30 -0
  190. data/js/datetime/timesheet/themes/default/timesheet.html +2 -0
  191. data/js/datetime/timesheet/timesheet.js +183 -0
  192. data/js/datetime/timesheet_item/js.inc +0 -0
  193. data/js/datetime/timesheet_item/themes/default/timesheet_item.css +42 -0
  194. data/js/datetime/timesheet_item/themes/default/timesheet_item.html +8 -0
  195. data/js/datetime/timesheet_item/timesheet_item.js +248 -0
  196. data/js/datetime/timesheet_item_edit/js.inc +0 -0
  197. data/js/datetime/timesheet_item_edit/timesheet_item_edit.js +274 -0
  198. data/js/foundation/application/application.js +208 -0
  199. data/js/foundation/application/js.inc +0 -0
  200. data/js/foundation/control/control.js +339 -0
  201. data/js/foundation/control/controldefaults/controldefaults.js +56 -0
  202. data/js/foundation/control/controldefaults/js.inc +0 -0
  203. data/js/foundation/control/dummyvalue/dummyvalue.js +51 -0
  204. data/js/foundation/control/dummyvalue/js.inc +0 -0
  205. data/js/foundation/control/dyncontrol/dyncontrol.js +500 -0
  206. data/js/foundation/control/dyncontrol/js.inc +0 -0
  207. data/js/foundation/control/dyncontrol/themes/default/dyncontrol.css +0 -0
  208. data/js/foundation/control/dyncontrol/themes/default/dyncontrol.html +0 -0
  209. data/js/foundation/control/eventresponder/eventresponder.js +750 -0
  210. data/js/foundation/control/eventresponder/js.inc +0 -0
  211. data/js/foundation/control/js.inc +0 -0
  212. data/js/foundation/control/valuematrix/js.inc +0 -0
  213. data/js/foundation/control/valuematrix/valuematrix.js +135 -0
  214. data/js/foundation/control/valueresponder/js.inc +0 -0
  215. data/js/foundation/control/valueresponder/valueresponder.js +79 -0
  216. data/js/foundation/eventmanager/eventmanager.js +991 -0
  217. data/js/foundation/eventmanager/js.inc +0 -0
  218. data/js/foundation/geom/point/js.inc +0 -0
  219. data/js/foundation/geom/point/point.js +202 -0
  220. data/js/foundation/geom/rect/js.inc +0 -0
  221. data/js/foundation/geom/rect/rect.js +651 -0
  222. data/js/foundation/json_renderer/js.inc +0 -0
  223. data/js/foundation/json_renderer/json_renderer.js +246 -0
  224. data/js/foundation/system/js.inc +0 -0
  225. data/js/foundation/system/system.js +381 -0
  226. data/js/foundation/thememanager/js.inc +0 -0
  227. data/js/foundation/thememanager/thememanager.js +393 -0
  228. data/js/foundation/value/js.inc +0 -0
  229. data/js/foundation/value/value.js +183 -0
  230. data/js/foundation/view/js.inc +0 -0
  231. data/js/foundation/view/markupview/js.inc +0 -0
  232. data/js/foundation/view/markupview/markupview.js +114 -0
  233. data/js/foundation/view/morphanimation/js.inc +0 -0
  234. data/js/foundation/view/morphanimation/morphanimation.js +237 -0
  235. data/js/foundation/view/view.js +1812 -0
  236. data/js/foundation/view/viewdefaults/js.inc +0 -0
  237. data/js/foundation/view/viewdefaults/viewdefaults.js +26 -0
  238. data/js/lists/checkboxlist/checkboxlist.js +171 -0
  239. data/js/lists/checkboxlist/js.inc +0 -0
  240. data/js/lists/listitems/js.inc +0 -0
  241. data/js/lists/listitems/listitems.js +88 -0
  242. data/js/lists/propertylist/js.inc +0 -0
  243. data/js/lists/propertylist/propertylist.js +326 -0
  244. data/js/lists/radiobuttonlist/js.inc +0 -0
  245. data/js/lists/radiobuttonlist/radiobuttonlist.js +116 -0
  246. data/js/util/reloadapp/js.inc +0 -0
  247. data/js/util/reloadapp/reloadapp.js +152 -0
  248. data/js/util/reloadapp/themes/default/reloadapp_warning-ie6.gif +0 -0
  249. data/js/util/reloadapp/themes/default/reloadapp_warning.png +0 -0
  250. data/js/util/sha/js.inc +0 -0
  251. data/js/util/sha/sha.js +426 -0
  252. data/js/views/centerview/centerview.js +75 -0
  253. data/js/views/centerview/js.inc +0 -0
  254. data/js/views/inlineview/inlineview.js +15 -0
  255. data/js/views/inlineview/js.inc +0 -0
  256. data/js/views/scrollview/js.inc +0 -0
  257. data/js/views/scrollview/scrollview.js +40 -0
  258. data/lib/conf/argv.rb +850 -0
  259. data/lib/conf/default.rb +219 -0
  260. data/lib/daemon/daemon.rb +387 -0
  261. data/lib/daemon/sigcomm.rb +64 -0
  262. data/lib/http/broker.rb +150 -0
  263. data/lib/http/rackup.rb +91 -0
  264. data/lib/http/request.rb +66 -0
  265. data/lib/http/response.rb +65 -0
  266. data/lib/plugins/dependencies.rb +285 -0
  267. data/lib/plugins/gui_plugin.rb +160 -0
  268. data/lib/plugins/guiparser.rb +123 -0
  269. data/lib/plugins/plugin.rb +438 -0
  270. data/lib/plugins/plugin_base.rb +162 -0
  271. data/lib/plugins/plugin_plugins.rb +81 -0
  272. data/lib/plugins/plugin_sqlite_db.rb +98 -0
  273. data/lib/plugins/pluginmanager.rb +635 -0
  274. data/lib/plugins/plugins.rb +169 -0
  275. data/lib/plugins/servlet.rb +108 -0
  276. data/lib/rsence.rb +32 -0
  277. data/lib/session/msg.rb +327 -0
  278. data/lib/session/sessionmanager.rb +522 -0
  279. data/lib/session/sessionstorage.rb +340 -0
  280. data/lib/transporter/transporter.rb +263 -0
  281. data/lib/util/gzstring.rb +9 -0
  282. data/lib/util/ruby19_fixes.rb +18 -0
  283. data/lib/values/hvalue.rb +378 -0
  284. data/lib/values/valuemanager.rb +172 -0
  285. data/plugins/client_pkg/client_pkg.rb +157 -0
  286. data/plugins/client_pkg/info.yaml +25 -0
  287. data/plugins/client_pkg/lib/client_pkg_build.rb +561 -0
  288. data/plugins/client_pkg/lib/client_pkg_cache.rb +50 -0
  289. data/plugins/client_pkg/lib/client_pkg_serve.rb +218 -0
  290. data/plugins/index_html/img/loading.gif +0 -0
  291. data/plugins/index_html/img/riassence.gif +0 -0
  292. data/plugins/index_html/index_html.rb +120 -0
  293. data/plugins/index_html/info.yaml +18 -0
  294. data/plugins/index_html/tmpl/index.html +15 -0
  295. data/plugins/main/info.yaml +18 -0
  296. data/plugins/main/js/main.js +84 -0
  297. data/plugins/main/main.rb +255 -0
  298. data/plugins/main/values.yaml +8 -0
  299. data/plugins/ticket/info.yaml +21 -0
  300. data/plugins/ticket/lib/common.rb +392 -0
  301. data/plugins/ticket/lib/favicon.rb +39 -0
  302. data/plugins/ticket/lib/file.rb +58 -0
  303. data/plugins/ticket/lib/img.rb +50 -0
  304. data/plugins/ticket/lib/objblob.rb +66 -0
  305. data/plugins/ticket/lib/rsrc.rb +34 -0
  306. data/plugins/ticket/lib/upload.rb +236 -0
  307. data/plugins/ticket/ticket.rb +333 -0
  308. data/setup/welcome/gui/welcome.yaml +92 -0
  309. data/setup/welcome/info.yaml +13 -0
  310. data/setup/welcome/text/welcome.html +9 -0
  311. data/setup/welcome/values.yaml +9 -0
  312. data/setup/welcome/welcome.rb +54 -0
  313. metadata +407 -0
@@ -0,0 +1,255 @@
1
+ ## RSence
2
+ # Copyright 2008 Riassence Inc.
3
+ # http://riassence.com/
4
+ #
5
+ # You should have received a copy of the GNU General Public License along
6
+ # with this software package. If not, contact licensing@riassence.com
7
+ ##
8
+
9
+
10
+ # The MainPlugin is accessible as +@plugins.main+ from other plugins.
11
+ #
12
+ # = MainPlugin provides mainly client setup and the following services:
13
+ # * The url of the client as a HValue, including the anchor.
14
+ # * Accessible via +msg.session[:main][:location_href]+
15
+ # * The local time of the client's web browser as a HValue, as seconds since epoch.
16
+ # * Accessible via +msg.session[:main][:client_time]+
17
+ # * Sequential loading. See {#delayed_call #delayed_call}
18
+ # * Provides the +#init_ui+ event for plugins that respond to it.
19
+ class MainPlugin < Plugin
20
+
21
+ # @private Internal structures, binds configuration data as instance variables
22
+ def init
23
+ super
24
+ @conf = ::RSence.config[:index_html]
25
+ @bconf = ::RSence.config[:broker_urls]
26
+ @goodbye_uri = File.join(@bconf[:hello],'goodbye')
27
+ end
28
+
29
+ # @private Internal structures, matches the "hello/goodbye" session termination request
30
+ def match( uri, request_type )
31
+ if request_type == :post and uri == @goodbye_uri
32
+ return true
33
+ end
34
+ return false
35
+ end
36
+
37
+ # @private Internal structures, score for the "hello/goodbye" session termination request
38
+ def score; 100; end
39
+
40
+ # @private Internal structures, handler for the "hello/goodbye" session termination request
41
+ def post( req, res, ses )
42
+ @plugins.sessions.expire_ses_by_req( req, res )
43
+ end
44
+
45
+ # @private url_responder gets called whenever the
46
+ # page location.href changes, enabled virtual uris
47
+ # to enable back/forward/bookmarking in browsers,
48
+ # when software is coded to support it.
49
+ #
50
+ # Client-side support is included in js/url_responder.js
51
+ #
52
+ # Also allows virtual-host -like behavior, if software is coded to support it.
53
+ def url_responder(msg,location_href)
54
+
55
+ ses = get_ses( msg )
56
+
57
+ # Virtual locations:
58
+ if location_href.data.include?('#')
59
+
60
+ # split 'http://localhost:8001/#/some_uri'
61
+ # -> ['http://localhost:8001/','/some_uri']
62
+ ses[:url] = location_href.data.split('#')
63
+
64
+ virtual_uri = ses[:url][1]
65
+
66
+ # built-in support for signing out, deletes the
67
+ # server-side session and reloads the page
68
+ if virtual_uri == '/sign_out'
69
+ resp_addr = @conf[:respond_address]
70
+ msg.expire_session()
71
+ msg.reply( [
72
+ 'COMM.Transporter.stop=true;',
73
+ "location.href=#{resp_addr.to_json};"
74
+ ].join('') )
75
+ end
76
+
77
+ else
78
+ ses[:url] = [location_href.data,nil]
79
+ end
80
+
81
+ # url_responder always accepts locations
82
+ return true
83
+
84
+ end
85
+
86
+
87
+ # @private new session initialization, called just once per session.
88
+ def init_ses(msg)
89
+ super
90
+ restore_ses( msg )
91
+ end
92
+
93
+ # @private called once when a session is restored using the cookie's ses_key
94
+ def restore_ses(msg)
95
+ super
96
+ ## Resets session data to defaults
97
+ ses = get_ses( msg )
98
+ ses[:boot] = 0
99
+ ses[:url] = [nil,nil]
100
+ ses[:delayed_calls] = []
101
+ ses[:poll_mode] = true
102
+ end
103
+
104
+ # Interface for adding delayed calls
105
+ #
106
+ # When adding a delayed call, use an Array to define a plugin/method with optional arguments that will be called on the next request. The client will call back immediately when a delayed call is pending. The first param of the method is a +msg+. Don't include the +msg+ of the current request in params, it will be inserted automatically for the delayed call.
107
+ #
108
+ # It can also be used for loading sequences to the client, when using a String as the +params+.
109
+ #
110
+ # == Format of +params+ for plugin callback:
111
+ # Array:: [ plugin_name, method_name, *args ]
112
+ #
113
+ # == Format of +params+ for javascript sequences:
114
+ # String:: Javascript to send
115
+ #
116
+ # Calls will be flushed per request with the following conditions:
117
+ # * At most four (4) delayed calls will be processed at a time
118
+ # * If the calls use more than 200ms combined, even less will be processed at a time
119
+ #
120
+ # @param [Message] msg The message instance.
121
+ # @param [Array, String] params The params of the delayed call.
122
+ #
123
+ # @return [nil]
124
+ def delayed_call( msg, params )
125
+ get_ses( msg )[:delayed_calls].push( params )
126
+ end
127
+
128
+ # @private Initializes the client-side COMM.urlResponder and sesWatcher
129
+ def boot0( msg, ses )
130
+
131
+ msg.reply read_js( 'main' )
132
+
133
+ msg.reply("ELEM.setStyle(0,'background-color','#{::RSence.config[:main_plugin][:bg_color]}');")
134
+
135
+ ## url_responder is bound in the client-space
136
+ ## to tell the server its status by updating its value
137
+ location_href_id = ses[:location_href].val_id.to_json
138
+ msg.reply "COMM.Values.values[#{location_href_id}].bind(COMM.urlResponder);"
139
+
140
+ ## This enables SesWatcher that changes :client_time every 60 seconds.
141
+ ## It makes the client to poll the server on regular intervals, when polling mode
142
+ ## is disabled.
143
+ # 5000ms = 5secs
144
+
145
+ client_time_id = ses[:client_time].val_id.to_json
146
+ poll_interval = ::RSence.config[:main_plugin][:server_poll_interval]
147
+ msg.reply "sesWatcher = COMM.SessionWatcher.nu(#{poll_interval},#{client_time_id});"
148
+
149
+ end
150
+
151
+ # @private Calls the init_ui method of each loaded plugin and removes the loading -message
152
+ def boot1( msg, ses )
153
+ # Delegates the init_ui method to each plugin to signal bootstrap completion.
154
+ msg.plugins.delegate( 'init_ui', msg ) unless ses[:dont_init_ui]
155
+ end
156
+
157
+ # @private
158
+ def dont_init_ui( msg )
159
+ get_ses( msg )[:dont_init_ui] = true
160
+ end
161
+
162
+ # @private Flushes commands in the :delayed_calls array
163
+ def flush_delayed( msg, ses )
164
+ ## Limits the amount of delayed calls to process to 4.
165
+ ## Prevents the client from choking even when the server
166
+ ## load is light.
167
+ if ses[:delayed_calls].size < 4
168
+ call_count = ses[:delayed_calls].size
169
+ else
170
+ call_count = 4
171
+ end
172
+
173
+ time_start = Time.now.to_f
174
+ time_taken = 0.0
175
+
176
+ ## process delayed calls, until:
177
+ ## - over 200ms of cpu time has been spent
178
+ ## - the :delayed_calls -array is empty
179
+ ## - call_count limit is reached
180
+ until time_taken > 0.2 or ses[:delayed_calls].size == 0 or call_count == 0
181
+ # gets the next call
182
+ delayed_call = ses[:delayed_calls].shift
183
+ if RSence.args[:debug]
184
+ puts "delayed_call: #{delayed_call.inspect}"
185
+ end
186
+ # strings are always javascript, used for segmenting client load
187
+ if delayed_call.class == String
188
+ msg.reply delayed_call
189
+ # arrays are plugin calls
190
+ elsif delayed_call.class == Array
191
+ # ['plugin_name', 'method_name'] pairs call the named plugin:method with just msg
192
+ if delayed_call.size == 2
193
+ (plugin_name,method_name) = delayed_call
194
+ msg.run(plugin_name,method_name,msg)
195
+ # if the array contains more items, they are used as additional method params
196
+ else
197
+ (plugin_name,method_name) = delayed_call[0..1]
198
+ method_params = delayed_call[2..-1]
199
+ msg.run(plugin_name,method_name,msg,*method_params)
200
+ end
201
+ end
202
+ ## calculates time taken
203
+ time_taken = Time.now.to_f - time_start
204
+ call_count -= 1
205
+ end
206
+ ## Sets the client into poll mode, unless the :delayed_calls -array is empty
207
+ if ses[:boot] > 1
208
+ if ses[:delayed_calls].empty?
209
+ end_polling( msg, ses )
210
+ else
211
+ start_polling( msg, ses )
212
+ end
213
+ end
214
+ end
215
+
216
+ # @private When nothing is delayed and the second poll has been made (init_ui called),
217
+ # sets the client to non-polling-mode, having only HValue
218
+ # changes trigger new requests. SesWatcher makes this happen
219
+ # regularly.
220
+ def end_polling( msg, ses )
221
+ if ses[:poll_mode] == true
222
+ msg.reply "COMM.Transporter.poll(0);"
223
+ ses[:poll_mode] = false
224
+ end
225
+ end
226
+
227
+ # @private Starts polling.
228
+ def start_polling( msg, ses )
229
+ if ses[:poll_mode] == false
230
+ msg.reply( "COMM.Transporter.poll(#{::RSence.config[:transporter_conf][:client_poll_priority]});" )
231
+ ses[:poll_mode] = true
232
+ end
233
+ end
234
+
235
+ # @private called on every request of an active, valid session
236
+ def idle(msg)
237
+
238
+ ses = get_ses( msg )
239
+
240
+ if ses[:boot] == 0
241
+ boot0( msg, ses )
242
+ elsif ses[:boot] == 1
243
+ boot1( msg, ses )
244
+ elsif not ses[:delayed_calls].empty?
245
+ flush_delayed( msg, ses )
246
+ elsif ses[:boot] > 1
247
+ end_polling( msg, ses )
248
+ end
249
+ ## Increment the counter forever.
250
+ ses[:boot] += 1
251
+ end
252
+
253
+ end
254
+
255
+
@@ -0,0 +1,8 @@
1
+ :client_time:
2
+ :value: 0
3
+ :restore_default: false
4
+ :location_href:
5
+ :value: ''
6
+ :restore_default: true
7
+ :responders:
8
+ - { :plugin: main, :method: url_responder }
@@ -0,0 +1,21 @@
1
+
2
+ # The human-readable product name of the package
3
+ title: Ticket services
4
+
5
+ # The human-readable version of the package
6
+ version: 2.0.0
7
+
8
+ # A brief description of the package (rdoc formatting supported)
9
+ description: |
10
+ This bundle provides various ticket services for serving files and file-like objects using disposable url's.
11
+
12
+ # A flag (when false) prevents the plugin from automatically reload when changed.
13
+ reloadable: false
14
+
15
+ # System version requirement.
16
+ sys_version: '>= 2.0.0'
17
+
18
+ category: :system
19
+
20
+ depends_on: :core
21
+
@@ -0,0 +1,392 @@
1
+ ## RSence
2
+ # Copyright 2008 Riassence Inc.
3
+ # http://riassence.com/
4
+ #
5
+ # You should have received a copy of the GNU General Public License along
6
+ # with this software package. If not, contact licensing@riassence.com
7
+ ##
8
+
9
+
10
+ # @private Inner workings of Ticket
11
+ module TicketService
12
+
13
+ # @private Inner workings of Ticket
14
+ module Common
15
+
16
+ def initialize
17
+ # storage for tickets to be expired by expiry time
18
+ # as the key and an array of ids in array as the value
19
+ @expires = {}
20
+ @expire_files = {}
21
+ @expire_blobobj = {}
22
+
23
+ # storage for disposable images
24
+ @imgs = {
25
+
26
+ # id is used as the uri
27
+ :by_id => {},
28
+
29
+ # list of image ids by session id
30
+ :ses_ids => {}
31
+ }
32
+
33
+ # storage for other disposable data
34
+ @files = {
35
+
36
+ # id is used as the uri
37
+ :by_id => {},
38
+
39
+ # list of image ids by session id
40
+ :ses_ids => {}
41
+ }
42
+
43
+ # an randgen instance used for generating ids (84B long)
44
+ @randgen = RandGen.new( 84 )
45
+
46
+ # supported image content types
47
+ @content_types = {
48
+ 'GIF' => 'image/gif',
49
+ 'PNG' => 'image/png',
50
+ 'JPG' => 'image/jpeg'
51
+ }
52
+
53
+ # static data, initially for invalid/not found error-gif
54
+ # also all serve_rsrc items
55
+ @raw_uris = {
56
+ 'invalid.gif' => ['image/gif','53',['749464839316700090000800000000004e7ebe129f400000000000c200000000700090000020c0c8f70a9c810e0229ea2da1a000b3'].pack('h*')],
57
+ 'favicon.ico' => ['image/gif','371',['749464839316010001005d00005e5e3dd1d1a1ca7dbf983cfeb9dc5ff8f848db1effbd1fff27279609a600cacae9e0e0d0dcaeff8e8fff030303010101848424afffff0000007be7008c8c9bffffff878b9e0eba712fcfffb2b282e9c6000d5900020202bd3a70ababbaf8f834f9f9f9f8f8f887fafafafa49060606fefefe0707700707074e3bc2939353ce6cd50404007d7d6cfafafa8edb34dcfcfc0f0d97fbfbfb000000000000000000000000000000000000000000000000000000000000000000000000000000000000129f401000000000c20000000001000100006009040801058c8420e91a258ca41744380506934656846910140e04051092ca650688d282bc2072bb5303e0728c2330d6fbb15a78249291bbf0d0811102353410124677285190b2e524e110e0f208b890a13176a480b0725211c889b16227a44101f0027931b1d171a745a010b2caea82f15845c9627182e2a2e050f5007af0f1a203329bf52be032d2213ca4501021501400b3'].pack('h*')]
58
+ }
59
+
60
+ @upload_slots = {
61
+ # upload slots
62
+ :by_id => {
63
+ # random key mime max_size session_id
64
+ # 'test123' => [ '*/*', 15000, 12 ]
65
+ },
66
+ # processed uploads
67
+ :uploaded => {
68
+ # same key as :by_id rsence_uploads:id
69
+ # 'test123' => [37483,37546,38759]
70
+ },
71
+ # upload ids by session id
72
+ :ses_ids => {
73
+ # 12 => ['test123']
74
+ }
75
+ }
76
+
77
+ @blob_objs = {
78
+ :by_id => {},
79
+ :ses_ids => {}
80
+ }
81
+
82
+ begin
83
+ db_uri = ::RSence.config[:database][:ses_db]
84
+ if db_uri.start_with?('sqlite://')
85
+ @db = Sequel.sqlite( db_uri.split('sqlite://')[1] )
86
+ else
87
+ @db = Sequel.connect( db_uri )
88
+ end
89
+ rescue => e
90
+ if RSence.args[:debug]
91
+ err_msg = [
92
+ "ERROR: TicketServices couldn't open database",
93
+ "#{e.class.to_s}, #{e.message}",
94
+ "Backtrace:",
95
+ "\t"+e.backtrace.join("\n\t")
96
+ ].join("\n")+"\n"
97
+ $stderr.write( err_msg )
98
+ elsif RSence.args[:verbose]
99
+ puts "Failed to open database '#{@db_uri}'."
100
+ puts "Run RSence in debug mode for full error output."
101
+ end
102
+ @upload_id = 0
103
+ @db = false
104
+ end
105
+ end
106
+
107
+ attr_accessor :raw_uris # :nodoc:
108
+ attr_accessor :imgs # :nodoc:
109
+ attr_accessor :content_types # :nodoc:
110
+
111
+ # Helper method to return the time formatted according to the HTTP RFC
112
+ def httime(time)
113
+ return time.gmtime.strftime('%a, %d %b %Y %H:%M:%S %Z')
114
+ end
115
+
116
+ # Disconnects connection to the database.
117
+ def shutdown # :nodoc:
118
+ @db.disconnect if @db
119
+ end
120
+
121
+ # Serves files and images by returning an URI. Content is given as second
122
+ # parameter. Optional third defaults to 'PNG' and defines the format.
123
+ # Optional fourth parameter is where there are two possibilities :img
124
+ # and :file, defaults to :img. URI works as an ID for data.
125
+ def serve( msg, content, format='PNG', type=:img )
126
+
127
+ # gets a new, unique identifier
128
+ ticket_id = @randgen.gen
129
+
130
+ # serve image
131
+ if type == :img
132
+
133
+ # makes sure the format is in uppper case
134
+ format.upcase!
135
+
136
+ # checks, that the format is a supported image type
137
+ unless @content_types.keys.include?( format )
138
+ puts "ImgServe.serve: invalid format (#{format.inspect})" if RSence.args[:verbose]
139
+ return File.join(::RSence.config[:broker_urls][:i],'invalid.gif')
140
+ end
141
+
142
+ # changes the format to GIF for IE6
143
+ format = 'GIF' if msg.ie6 and format == 'PNG'
144
+
145
+ # stores the image data and meta-data ready to be served
146
+ storage_hash = @imgs
147
+ storage_arr = [format,0,content,msg.ses_id]
148
+
149
+ # return an uri that will respond to the data
150
+ uri = File.join(::RSence.config[:broker_urls][:i],"#{ticket_id}.#{format.downcase}")
151
+
152
+ # serve file
153
+ elsif type == :file
154
+
155
+ # re-map content_type and filename meta-data from format
156
+ (content_type, filename) = format
157
+
158
+ # content size for the header
159
+ content_size = content.size.to_s
160
+
161
+ storage_hash = @files
162
+ storage_arr = [content_type,content_size,content,msg.ses_id,filename]
163
+
164
+ uri = File.join(::RSence.config[:broker_urls][:f],ticket_id)
165
+ end
166
+
167
+ # makes sure, that the storage array has a sub-array for sessions (to aid session-based cleanup)
168
+ storage_hash[:ses_ids][msg.ses_id] = [] unless @imgs[:ses_ids].has_key?(msg.ses_id)
169
+
170
+ # adds the id to the session-specific storage
171
+ storage_hash[:ses_ids][msg.ses_id].push( ticket_id )
172
+
173
+ storage_hash[:by_id][ticket_id] = storage_arr
174
+
175
+ return uri
176
+ end
177
+
178
+ # Alias for +Ticketserve#serve+.
179
+ alias serve_img serve
180
+
181
+ # Flushes disposable storage when the session expires. Session id is given
182
+ # as a parameter.
183
+ def expire_ses( ses_id ) # :nodoc:
184
+
185
+ # flush images by session id
186
+ if @imgs[:ses_ids].has_key?(ses_id)
187
+
188
+ # goes through the array, until it's empty
189
+ until @imgs[:ses_ids][ses_id].empty?
190
+ img_id = @imgs[:ses_ids][ses_id].shift
191
+ del_img( img_id, ses_id )
192
+ end
193
+
194
+ # finally, removes the session id
195
+ @imgs[:ses_ids].delete( ses_id )
196
+ end
197
+
198
+ # flush other data by session id
199
+ if @files[:ses_ids].has_key?(ses_id)
200
+
201
+ # goes through the array, until it's empty
202
+ until @files[:ses_ids][ses_id].empty?
203
+ file_id = @files[:ses_ids][ses_id].shift
204
+ del_file( file_id, ses_id )
205
+ end
206
+
207
+ # finally, removes the session id
208
+ @files[:ses_ids].delete( ses_id )
209
+ end
210
+
211
+ if @upload_slots[:ses_ids].has_key?(ses_id)
212
+ # goes through the array, until it's empty
213
+ until @upload_slots[:ses_ids][ses_id].empty?
214
+ ticket_id = @upload_slots[:ses_ids][ses_id].shift
215
+ del_uploads( ticket_id, ses_id )
216
+ end
217
+
218
+ # finally, removes the session id
219
+ @upload_slots[:ses_ids].delete( ses_id )
220
+ end
221
+
222
+ if @blob_objs[:ses_ids].has_key?(ses_id)
223
+ # goes through the array, until it's empty
224
+ until @blob_objs[:ses_ids][ses_id].empty?
225
+ ticket_id = @blob_objs[:ses_ids][ses_id].shift
226
+ del_blobobj( ticket_id, ses_id )
227
+ end
228
+
229
+ # finally, removes the session id
230
+ @blob_objs[:ses_ids].delete( ses_id )
231
+ end
232
+
233
+ end
234
+
235
+ # Serves data based on get request. Is used automatically by +Broker+.
236
+ def get_ticket( req, res, type=:img ) # :nodoc:
237
+
238
+ is_invalid = true
239
+
240
+ if type == :img
241
+
242
+ img_id = req.unparsed_uri.match(/^#{::RSence.config[:broker_urls][:i]}(.*)$/)[1]
243
+
244
+ if img_id == nil
245
+ puts "ImgServe.fetch_img: invalid uri#1 (#{req.unparsed_uri.inspect})" if RSence.args[:verbose]
246
+ img_id = 'invalid.gif'
247
+ end
248
+
249
+ img_id = img_id.split('.')[0]
250
+
251
+ if img_id == nil
252
+ puts "ImgServe.fetch_img: invalid uri#2 (#{req.unparsed_uri.inspect})" if RSence.args[:verbose]
253
+ img_id = 'invalid.gif'
254
+
255
+ elsif img_id.size != 84
256
+ puts "ImgServe.fetch_img: invalid img_id (#{img_id.inspect})" if RSence.args[:verbose]
257
+ img_id = 'invalid.gif'
258
+ end
259
+
260
+ if @raw_uris.include?(img_id)
261
+ (content_type,content_size,content) = @raw_uris[img_id]
262
+
263
+ elsif @imgs[:by_id].include?(img_id)
264
+
265
+ (format,content_size_zero,img_data,ses_id) = @imgs[:by_id][img_id]
266
+
267
+ # renders the Magick::Image object
268
+ content = img_data.to_blob {
269
+ self.format = format
270
+ }
271
+
272
+ # content size for the header
273
+ content_size = content.size.to_s
274
+
275
+ # content type for the header
276
+ content_type = @content_types[format]
277
+
278
+ if req.header.has_key?('keep-alive') and req.header['keep-alive'].size > 0
279
+ keep_alive = req.header['keep-alive'][0].to_i
280
+ keep_alive = 10 if keep_alive < 10
281
+ keep_alive = 600 if keep_alive > 600
282
+ push_keepalive( img_id, keep_alive )
283
+ expire_keepalives
284
+ else
285
+ del_img( img_id, ses_id )
286
+ end
287
+ else
288
+ (content_type,content_size,content) = @raw_uris['invalid.gif']
289
+ end
290
+
291
+
292
+ elsif type == :file
293
+ file_id = req.unparsed_uri.match(/^#{::RSence.config[:broker_urls][:f]}(.*)$/)[1]
294
+ if file_id == nil
295
+ puts "fileServe.fetch_file: invalid uri#1 (#{req.unparsed_uri.inspect})" if RSence.args[:verbose]
296
+ file_id = 'invalid.gif'
297
+ end
298
+ file_id = file_id.split('.')[0]
299
+ if file_id == nil
300
+ puts "fileServe.fetch_file: invalid uri#2 (#{req.unparsed_uri.inspect})" if RSence.args[:verbose]
301
+ file_id = 'invalid.gif'
302
+ elsif file_id.size != 84
303
+ puts "fileServe.fetch_file: invalid file_id (#{file_id.inspect})" if RSence.args[:verbose]
304
+ file_id = 'invalid.gif'
305
+ end
306
+ if @raw_uris.include?(file_id)
307
+ (content_type,content_size,content) = @raw_uris[file_id]
308
+ elsif @files[:by_id].include?(file_id)
309
+ (content_type,content_size,content,ses_id) = @files[:by_id][file_id]
310
+ if req.header.has_key?('keep-alive') and req.header['keep-alive'].size > 0
311
+ keep_alive = req.header['keep-alive'][0].to_i
312
+ keep_alive = 10 if keep_alive < 10
313
+ keep_alive = 600 if keep_alive > 600
314
+ push_keepalive_file( file_id, keep_alive )
315
+ expire_keepalive_files
316
+ else
317
+ del_file( file_id, ses_id )
318
+ end
319
+ else
320
+ (content_type,content_size,content) = @raw_uris['invalid.gif']
321
+ end
322
+
323
+ elsif type == :blobobj
324
+ blobobj_id = req.unparsed_uri.match(/^#{::RSence.config[:broker_urls][:b]}(.*)$/)[1]
325
+ if blobobj_id == nil
326
+ puts "fileServe.fetch_blobobj: invalid uri#1 (#{req.unparsed_uri.inspect})" if RSence.args[:verbose]
327
+ blobobj_id = 'invalid.gif'
328
+ end
329
+ if blobobj_id == nil
330
+ puts "fileServe.fetch_blobobj: invalid uri#2 (#{req.unparsed_uri.inspect})" if RSence.args[:verbose]
331
+ blobobj_id = 'invalid.gif'
332
+ elsif blobobj_id.size != 84
333
+ puts "fileServe.fetch_blobobj: invalid blobobj_id (#{blobobj_id.inspect})" if RSence.args[:verbose]
334
+ blobobj_id = 'invalid.gif'
335
+ end
336
+ if @raw_uris.include?(blobobj_id)
337
+ content_type = @raw_uris[blobobj_id].mime
338
+ content_size = @raw_uris[blobobj_id].size
339
+ content = @raw_uris[blobobj_id].data
340
+ elsif @blob_objs[:by_id].include?(blobobj_id)
341
+ (ses_id, blobobj) = @blob_objs[:by_id][blobobj_id]
342
+ content_type = blobobj.mime
343
+ content_size = blobobj.size
344
+ content = blobobj.data
345
+ if req.header.has_key?('keep-alive') and req.header['keep-alive'].size > 0
346
+ keep_alive = req.header['keep-alive'][0].to_i
347
+ keep_alive = 10 if keep_alive < 10
348
+ keep_alive = 600 if keep_alive > 600
349
+ push_keepalive_blobobj( blobobj_id, keep_alive )
350
+ expire_keepalive_blobobjs
351
+ else
352
+ del_blobobj( blobobj_id, ses_id )
353
+ end
354
+ else
355
+ (content_type,content_size,content) = @raw_uris['invalid.gif']
356
+ end
357
+
358
+ elsif type == :rsrc
359
+ rsrc_id = req.unparsed_uri.match(/^#{::RSence.config[:broker_urls][:d]}(.*)$/)[1]
360
+ if rsrc_id == nil
361
+ puts "rsrcServe.fetch_rsrc: invalid uri#1 (#{req.unparsed_uri.inspect})" if RSence.args[:verbose]
362
+ rsrc_id = 'invalid.gif'
363
+ end
364
+ rsrc_id = rsrc_id.split('.')[0]
365
+ if rsrc_id == nil
366
+ puts "rsrcServe.fetch_rsrc: invalid uri#2 (#{req.unparsed_uri.inspect})" if RSence.args[:verbose]
367
+ rsrc_id = 'invalid.gif'
368
+ elsif rsrc_id.size != 84
369
+ puts "rsrcServe.fetch_rsrc: invalid rsrc_id (#{rsrc_id.inspect})" if RSence.args[:verbose]
370
+ rsrc_id = 'invalid.gif'
371
+ end
372
+ if @raw_uris.include?(rsrc_id)
373
+ (content_type,content_size,content) = @raw_uris[rsrc_id]
374
+ else
375
+ (content_type,content_size,content) = @raw_uris['invalid.gif']
376
+ end
377
+ end
378
+
379
+ res.status = 200
380
+
381
+ res['Content-Type'] = content_type
382
+ res['Content-Length'] = content_size
383
+
384
+ res['Date'] = httime( Time.now )
385
+ res['Expires'] = httime(Time.now+::RSence.config[:cache_expire])
386
+
387
+ res.body = content
388
+
389
+ end
390
+
391
+ end
392
+ end