deltacloud-core 0.3.0 → 0.4.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (242) hide show
  1. data/LICENSE +145 -0
  2. data/NOTICE +10 -1
  3. data/Rakefile +50 -2
  4. data/bin/deltacloudd +111 -14
  5. data/config/addresses.xml +14 -0
  6. data/config/condor.yaml +30 -0
  7. data/config/drivers/azure.yaml +3 -0
  8. data/config/drivers/condor.yaml +3 -0
  9. data/config/{drivers.yaml → drivers/ec2.yaml} +5 -34
  10. data/config/drivers/eucalyptus.yaml +8 -0
  11. data/config/drivers/gogrid.yaml +3 -0
  12. data/config/drivers/mock.yaml +3 -0
  13. data/config/drivers/opennebula.yaml +4 -0
  14. data/config/drivers/rackspace.yaml +3 -0
  15. data/config/drivers/rhevm.yaml +3 -0
  16. data/config/drivers/rimuhosting.yaml +3 -0
  17. data/config/drivers/sbc.yaml +2 -0
  18. data/config/drivers/terremark.yaml +3 -0
  19. data/config/drivers/vsphere.yaml +8 -0
  20. data/deltacloud-core.gemspec +13 -5
  21. data/deltacloud.rb +4 -2
  22. data/lib/deltacloud/backend_capability.rb +2 -2
  23. data/lib/deltacloud/base_driver/base_driver.rb +23 -52
  24. data/lib/deltacloud/base_driver/exceptions.rb +168 -0
  25. data/lib/deltacloud/base_driver/features.rb +31 -12
  26. data/lib/deltacloud/base_driver/mock_driver.rb +2 -1
  27. data/lib/deltacloud/core_ext/string.rb +2 -0
  28. data/lib/deltacloud/drivers/azure/azure_driver.rb +5 -5
  29. data/lib/deltacloud/drivers/condor/condor_client.rb +273 -0
  30. data/lib/deltacloud/drivers/condor/condor_driver.rb +236 -0
  31. data/lib/deltacloud/drivers/condor/ip_agents/confserver.rb +75 -0
  32. data/lib/deltacloud/drivers/condor/ip_agents/default.rb +84 -0
  33. data/lib/deltacloud/drivers/ec2/ec2_driver.rb +326 -95
  34. data/lib/deltacloud/drivers/ec2/ec2_mock_driver.rb +3 -3
  35. data/lib/deltacloud/drivers/eucalyptus/eucalyptus_driver.rb +40 -8
  36. data/lib/deltacloud/drivers/gogrid/gogrid_client.rb +7 -7
  37. data/lib/deltacloud/drivers/gogrid/gogrid_driver.rb +42 -25
  38. data/lib/deltacloud/drivers/mock/data/{buckets/blobs → blobs}/blob1.yml +6 -4
  39. data/lib/deltacloud/drivers/mock/data/{buckets/blobs → blobs}/blob2.yml +7 -5
  40. data/lib/deltacloud/drivers/mock/data/{buckets/blobs → blobs}/blob3.yml +6 -4
  41. data/lib/deltacloud/drivers/mock/data/{buckets/blobs → blobs}/blob4.yml +6 -4
  42. data/lib/deltacloud/drivers/mock/data/{buckets/blobs → blobs}/blob5.yml +6 -4
  43. data/lib/deltacloud/drivers/mock/data/buckets/bucket1.yml +7 -1
  44. data/lib/deltacloud/drivers/mock/data/buckets/bucket2.yml +6 -1
  45. data/lib/deltacloud/drivers/mock/data/images/img1.yml +6 -2
  46. data/lib/deltacloud/drivers/mock/data/images/img2.yml +6 -2
  47. data/lib/deltacloud/drivers/mock/data/images/img3.yml +6 -2
  48. data/lib/deltacloud/drivers/mock/data/instances/inst0.yml +11 -10
  49. data/lib/deltacloud/drivers/mock/data/instances/inst1.yml +14 -7
  50. data/lib/deltacloud/drivers/mock/data/instances/inst2.yml +14 -7
  51. data/lib/deltacloud/drivers/mock/data/storage_snapshots/snap1.yml +3 -2
  52. data/lib/deltacloud/drivers/mock/data/storage_snapshots/snap2.yml +3 -2
  53. data/lib/deltacloud/drivers/mock/data/storage_snapshots/snap3.yml +3 -2
  54. data/lib/deltacloud/drivers/mock/data/storage_volumes/vol1.yml +4 -3
  55. data/lib/deltacloud/drivers/mock/data/storage_volumes/vol2.yml +4 -3
  56. data/lib/deltacloud/drivers/mock/data/storage_volumes/vol3.yml +4 -3
  57. data/lib/deltacloud/drivers/mock/mock_client.rb +101 -0
  58. data/lib/deltacloud/drivers/mock/mock_driver.rb +367 -429
  59. data/lib/deltacloud/drivers/opennebula/opennebula_driver.rb +6 -0
  60. data/lib/deltacloud/drivers/rackspace/rackspace_driver.rb +59 -9
  61. data/lib/deltacloud/drivers/rhevm/rhevm_client.rb +62 -8
  62. data/lib/deltacloud/drivers/rhevm/rhevm_driver.rb +100 -45
  63. data/lib/deltacloud/drivers/rimuhosting/rimuhosting_client.rb +3 -2
  64. data/lib/deltacloud/drivers/rimuhosting/rimuhosting_driver.rb +8 -11
  65. data/lib/deltacloud/drivers/sbc/sbc_client.rb +6 -6
  66. data/lib/deltacloud/drivers/sbc/sbc_driver.rb +16 -0
  67. data/lib/deltacloud/drivers/terremark/terremark_driver.rb +17 -12
  68. data/lib/deltacloud/drivers/vsphere/vsphere_client.rb +140 -0
  69. data/lib/deltacloud/drivers/vsphere/vsphere_driver.rb +405 -0
  70. data/lib/deltacloud/drivers/vsphere/vsphere_filemanager.rb +182 -0
  71. data/lib/deltacloud/hardware_profile.rb +1 -1
  72. data/lib/deltacloud/helpers.rb +2 -1
  73. data/lib/deltacloud/helpers/application_helper.rb +92 -20
  74. data/lib/deltacloud/helpers/blob_stream.rb +160 -12
  75. data/lib/deltacloud/helpers/conversion_helper.rb +6 -2
  76. data/lib/deltacloud/helpers/json_helper.rb +31 -0
  77. data/lib/deltacloud/models/address.rb +28 -0
  78. data/lib/deltacloud/models/base_model.rb +5 -1
  79. data/lib/deltacloud/models/blob.rb +1 -1
  80. data/lib/deltacloud/models/bucket.rb +10 -0
  81. data/lib/deltacloud/models/firewall.rb +22 -0
  82. data/lib/deltacloud/models/firewall_rule.rb +23 -0
  83. data/lib/deltacloud/models/image.rb +12 -0
  84. data/lib/deltacloud/models/instance.rb +20 -2
  85. data/lib/deltacloud/models/key.rb +1 -1
  86. data/lib/deltacloud/runner.rb +3 -3
  87. data/lib/deltacloud/validation.rb +3 -7
  88. data/lib/drivers.rb +7 -1
  89. data/lib/sinatra/body_proxy.rb +34 -0
  90. data/lib/sinatra/lazy_auth.rb +5 -0
  91. data/lib/sinatra/rabbit.rb +54 -31
  92. data/lib/sinatra/rack_accept.rb +157 -0
  93. data/lib/sinatra/rack_date.rb +38 -0
  94. data/lib/sinatra/rack_etag.rb +2 -3
  95. data/lib/sinatra/rack_matrix_params.rb +51 -29
  96. data/lib/sinatra/rack_runtime.rb +1 -1
  97. data/lib/sinatra/rack_syslog.rb +86 -0
  98. data/lib/sinatra/url_for.rb +14 -1
  99. data/public/images/address.png +0 -0
  100. data/public/images/balancer.png +0 -0
  101. data/public/images/blob.png +0 -0
  102. data/public/images/bucket.png +0 -0
  103. data/public/images/cloud.png +0 -0
  104. data/public/images/firewall.png +0 -0
  105. data/public/images/image.png +0 -0
  106. data/public/images/key.png +0 -0
  107. data/public/images/machine.png +0 -0
  108. data/public/images/profile.png +0 -0
  109. data/public/images/realm.png +0 -0
  110. data/public/images/snapshot.png +0 -0
  111. data/public/images/volume.png +0 -0
  112. data/public/javascripts/application.js +119 -16
  113. data/public/javascripts/jquery.min.js +18 -0
  114. data/public/javascripts/jquery.mobile-1.0b1.min.js +146 -0
  115. data/public/stylesheets/compiled/application.css +8 -0
  116. data/public/stylesheets/images/ajax-loader.png +0 -0
  117. data/public/{images → stylesheets/images}/bread-bg.png +0 -0
  118. data/public/{images → stylesheets/images}/error.png +0 -0
  119. data/public/{images → stylesheets/images}/grid.png +0 -0
  120. data/public/stylesheets/images/icon-search-black.png +0 -0
  121. data/public/stylesheets/images/icons-18-black.png +0 -0
  122. data/public/stylesheets/images/icons-18-white.png +0 -0
  123. data/public/stylesheets/images/icons-36-black.png +0 -0
  124. data/public/stylesheets/images/icons-36-white.png +0 -0
  125. data/public/{images → stylesheets/images}/logo-wide.png +0 -0
  126. data/public/{images → stylesheets/images}/pending.png +0 -0
  127. data/public/{images → stylesheets/images}/rails.png +0 -0
  128. data/public/{images → stylesheets/images}/running.png +0 -0
  129. data/public/{images → stylesheets/images}/stopped.png +0 -0
  130. data/public/{images → stylesheets/images}/topbar-bg.png +0 -0
  131. data/public/stylesheets/jquery.mobile-1.0b1.min.css +8 -0
  132. data/public/stylesheets/new.css +53 -0
  133. data/server.rb +487 -175
  134. data/support/condor/bash/cached_images.sh +8 -0
  135. data/support/condor/bash/cloud_exit_hook.sh +17 -0
  136. data/support/condor/bash/cloud_functions +175 -0
  137. data/support/condor/bash/cloud_prepare_hook.sh +20 -0
  138. data/support/condor/bash/libvirt_cloud_script.sh +13 -0
  139. data/support/condor/config/50condor_cloud.config +37 -0
  140. data/support/condor/config/50condor_cloud_node.config +37 -0
  141. data/support/condor/config/condor-cloud +2 -0
  142. data/support/condor/config/condor_config.local +44 -0
  143. data/support/fedora/deltacloud-core +48 -26
  144. data/support/fedora/deltacloud-core-config +26 -0
  145. data/support/fedora/deltacloud-core.spec +314 -68
  146. data/support/fedora/deltacloudd-fedora +5 -0
  147. data/tests/common.rb +34 -4
  148. data/tests/drivers/mock/api_test.rb +3 -3
  149. data/tests/drivers/mock/images_test.rb +12 -0
  150. data/tests/drivers/mock/instances_test.rb +2 -0
  151. data/tests/rabbit_test.rb +2 -2
  152. data/views/addresses/_address.html.haml +6 -0
  153. data/views/addresses/associate.html.haml +12 -0
  154. data/views/addresses/index.html.haml +9 -0
  155. data/views/addresses/index.xml.haml +4 -0
  156. data/views/addresses/show.html.haml +21 -0
  157. data/views/addresses/show.xml.haml +14 -0
  158. data/views/api/show.html.haml +6 -11
  159. data/views/api/show.xml.haml +2 -0
  160. data/views/blobs/new.html.haml +24 -23
  161. data/views/blobs/show.html.haml +30 -31
  162. data/views/buckets/index.html.haml +9 -21
  163. data/views/buckets/index.xml.haml +3 -7
  164. data/views/buckets/new.html.haml +13 -12
  165. data/views/buckets/show.html.haml +22 -22
  166. data/views/buckets/show.xml.haml +5 -3
  167. data/views/docs/collection.html.haml +23 -34
  168. data/views/docs/collection.xml.haml +2 -2
  169. data/views/docs/index.html.haml +9 -13
  170. data/views/docs/index.xml.haml +1 -1
  171. data/views/docs/operation.html.haml +28 -38
  172. data/views/docs/operation.xml.haml +1 -1
  173. data/views/drivers/index.html.haml +8 -13
  174. data/views/drivers/show.html.haml +18 -18
  175. data/views/error.html.haml +32 -27
  176. data/views/errors/400.html.haml +41 -0
  177. data/views/errors/{validation_failure.xml.haml → 400.xml.haml} +0 -4
  178. data/views/errors/401.html.haml +41 -0
  179. data/views/errors/{auth_exception.xml.haml → 401.xml.haml} +0 -0
  180. data/views/errors/403.html.haml +42 -0
  181. data/views/errors/{not_allowed.xml.haml → 403.xml.haml} +0 -0
  182. data/views/errors/404.html.haml +29 -0
  183. data/views/errors/{not_found.xml.haml → 404.xml.haml} +1 -1
  184. data/views/errors/405.html.haml +29 -0
  185. data/views/errors/405.xml.haml +5 -0
  186. data/views/errors/500.html.haml +43 -0
  187. data/views/errors/500.xml.haml +5 -0
  188. data/views/errors/502.html.haml +43 -0
  189. data/views/errors/{backend_error.xml.haml → 502.xml.haml} +1 -2
  190. data/views/errors/backend_capability_failure.html.haml +27 -9
  191. data/views/firewalls/index.html.haml +15 -0
  192. data/views/firewalls/index.xml.haml +28 -0
  193. data/views/firewalls/new.html.haml +11 -0
  194. data/views/firewalls/new_rule.html.haml +20 -0
  195. data/views/firewalls/show.html.haml +42 -0
  196. data/views/firewalls/show.xml.haml +26 -0
  197. data/views/hardware_profiles/index.html.haml +15 -23
  198. data/views/hardware_profiles/show.html.haml +22 -18
  199. data/views/images/index.html.haml +11 -23
  200. data/views/images/index.xml.haml +4 -13
  201. data/views/images/new.html.haml +12 -13
  202. data/views/images/show.html.haml +26 -20
  203. data/views/images/show.xml.haml +2 -1
  204. data/views/instance_states/show.html.haml +21 -25
  205. data/views/instances/index.html.haml +13 -30
  206. data/views/instances/index.xml.haml +2 -23
  207. data/views/instances/new.html.haml +83 -88
  208. data/views/instances/show.html.haml +53 -55
  209. data/views/instances/show.xml.haml +12 -10
  210. data/views/keys/index.html.haml +13 -24
  211. data/views/keys/new.html.haml +7 -7
  212. data/views/keys/show.html.haml +26 -21
  213. data/views/layout.html.haml +28 -27
  214. data/views/load_balancers/index.html.haml +11 -31
  215. data/views/load_balancers/index.xml.haml +0 -1
  216. data/views/load_balancers/new.html.haml +1 -1
  217. data/views/load_balancers/show.html.haml +33 -34
  218. data/views/load_balancers/show.xml.haml +2 -2
  219. data/views/realms/index.html.haml +11 -24
  220. data/views/realms/index.xml.haml +2 -8
  221. data/views/realms/show.html.haml +17 -15
  222. data/views/realms/show.xml.haml +2 -1
  223. data/views/storage_snapshots/index.html.haml +11 -21
  224. data/views/storage_snapshots/index.xml.haml +2 -5
  225. data/views/storage_snapshots/new.html.haml +1 -1
  226. data/views/storage_snapshots/show.html.haml +21 -13
  227. data/views/storage_snapshots/show.xml.haml +2 -1
  228. data/views/storage_volumes/index.html.haml +11 -34
  229. data/views/storage_volumes/new.html.haml +1 -1
  230. data/views/storage_volumes/show.html.haml +33 -27
  231. data/views/storage_volumes/show.xml.haml +2 -1
  232. metadata +266 -178
  233. data/lib/sinatra/respond_to.rb +0 -248
  234. data/support/fedora/deltacloudd +0 -128
  235. data/support/fedora/rubygem-deltacloud-core.spec +0 -127
  236. data/views/accounts/index.html.haml +0 -11
  237. data/views/accounts/show.html.haml +0 -30
  238. data/views/errors/auth_exception.html.haml +0 -8
  239. data/views/errors/backend_error.html.haml +0 -22
  240. data/views/errors/not_allowed.html.haml +0 -6
  241. data/views/errors/not_found.html.haml +0 -6
  242. data/views/errors/validation_failure.html.haml +0 -11
@@ -0,0 +1,157 @@
1
+ # respond_to (The MIT License)
2
+
3
+ # Permission is hereby granted, free of charge, to any person obtaining a copy of this software
4
+ # and associated documentation files (the 'Software'), to deal in the Software without restriction,
5
+ # including without limitation the rights to use, copy, modify, merge, publish, distribute,
6
+ # sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is
7
+ # furnished to do so, subject to the following conditions:
8
+ #
9
+ # THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT
10
+ # NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
11
+ # NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
12
+ # DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
13
+ # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE
14
+
15
+ require 'sinatra/base'
16
+ require 'rack/accept'
17
+
18
+ use Rack::Accept
19
+
20
+ module Rack
21
+
22
+ module RespondTo
23
+
24
+ # This method is triggered after this helper is registred
25
+ # within Sinatra.
26
+ # We need to overide the default render method to supply correct path to the
27
+ # template, since Sinatra is by default looking in the current __FILE__ path
28
+ def self.registered(app)
29
+ app.helpers Rack::RespondTo::Helpers
30
+ app.class_eval do
31
+ alias :render_without_format :render
32
+ def render(*args, &block)
33
+ begin
34
+ assumed_layout = args[1] == :layout
35
+ args[1] = "#{args[1]}.#{@media_type}".to_sym if args[1].is_a?(::Symbol)
36
+ render_without_format *args, &block
37
+ rescue Errno::ENOENT => e
38
+ raise "ERROR: Missing template: #{args[1]}.#{args[0]}" unless assumed_layout
39
+ raise e
40
+ end
41
+ end
42
+ private :render
43
+ end
44
+ end
45
+
46
+ module Helpers
47
+
48
+ # This code was inherited from respond_to plugin
49
+ # http://github.com/cehoffman/sinatra-respond_to
50
+ #
51
+ # This method is used to overide the default content_type returned from
52
+ # rack-accept middleware.
53
+ def self.included(klass)
54
+ klass.class_eval do
55
+ alias :content_type_without_save :content_type
56
+ def content_type(*args)
57
+ content_type_without_save *args
58
+ request.env['rack-accept.formats'] = { args.first.to_sym => 1 }
59
+ response['Content-Type']
60
+ end
61
+ end
62
+ end
63
+
64
+ def accepting_formats
65
+ request.env['rack-accept.formats']
66
+ end
67
+
68
+ def static_file?(path)
69
+ public_dir = File.expand_path(options.public)
70
+ path = File.expand_path(File.join(public_dir, unescape(path)))
71
+ path[0, public_dir.length] == public_dir && File.file?(path)
72
+ end
73
+
74
+ def respond_to(&block)
75
+ wants = {}
76
+ def wants.method_missing(type, *args, &handler)
77
+ self[type] = handler
78
+ end
79
+ yield wants
80
+ @media_type = accepting_formats.to_a.sort { |a,b| a[1]<=>b[1] }.reverse.select do |format, priority|
81
+ wants.keys.include?(format) == true
82
+ end.first
83
+ if @media_type and @media_type[0]
84
+ @media_type = @media_type[0]
85
+ headers 'Content-Type' => Rack::MediaType::ACCEPTED_MEDIA_TYPES[@media_type][:return]
86
+ wants[@media_type.to_sym].call if wants[@media_type.to_sym]
87
+ else
88
+ headers 'Content-Type' => nil
89
+ status 406
90
+ end
91
+ end
92
+
93
+ end
94
+
95
+ end
96
+
97
+ class MediaType < Sinatra::Base
98
+
99
+ include Rack::RespondTo::Helpers
100
+
101
+ # Define supported media types here
102
+ # The :return key stands for content-type which will be returned
103
+ # The :match key stands for the matching Accept header
104
+ ACCEPTED_MEDIA_TYPES = {
105
+ :xml => { :return => 'application/xml', :match => ['application/xml', 'text/xml'] },
106
+ :json => { :return => 'application/json', :match => ['application/json'] },
107
+ :html => { :return => 'text/html', :match => ['application/xhtml+xml', 'text/html', '*/*'] },
108
+ :png => { :return => 'image/png', :match => ['image/png'] },
109
+ :gv => { :return => 'application/ghostscript', :match => ['application/ghostscript'] }
110
+ }
111
+
112
+ def call(env)
113
+ accept, index = env['rack-accept.request'], {}
114
+
115
+ # Skip everything when 'format' parameter is set in URL
116
+ if env['rack.request.query_hash']["format"]
117
+ media_type = case env['rack.request.query_hash']["format"]
118
+ when 'html' then :html
119
+ when 'xml' then :xml
120
+ when 'json' then :json
121
+ when 'gv' then :gv
122
+ when 'png' then :png
123
+ end
124
+ index[media_type] = 1 if media_type
125
+ else
126
+ # Sort all requested media types in Accept using their 'q' values
127
+ sorted_media_types = accept.media_type.qvalues.to_a.sort{ |a,b| a[1]<=>b[1] }.collect { |t| t.first }
128
+ # If Accept header is missing or is empty, fallback to XML format
129
+ sorted_media_types << 'application/xml' if sorted_media_types.empty?
130
+ # Choose the right format with the media type according to the priority
131
+ ACCEPTED_MEDIA_TYPES.each do |format, definition|
132
+ definition[:match].each do |media_type|
133
+ break if index[format] = sorted_media_types.index(media_type)
134
+ end
135
+ end
136
+ # Reject formats with no/nil priority
137
+ index.reject! { |format, priority| not priority }
138
+ end
139
+
140
+ #puts sorted_media_types.inspect
141
+ #puts index.inspect
142
+
143
+ # If after all we don't have any matching format assume that client has
144
+ # requested unknown/wrong media type and throw an 406 error with no body
145
+ if index.keys.empty?
146
+ status, headers, response = 406, {}, ""
147
+ else
148
+ env['rack-accept.formats'] = index
149
+ status, headers, response = @app.call(env)
150
+ end
151
+ [status, headers, response]
152
+ end
153
+
154
+ end
155
+
156
+ end
157
+
@@ -0,0 +1,38 @@
1
+
2
+ # Copyright (c) 2008 The Committers
3
+
4
+ # Permission is hereby granted, free of charge, to any person obtaining a copy
5
+ # of this software and associated documentation files (the "Software"), to
6
+ # deal in the Software without restriction, including without limitation the
7
+ # rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
8
+ # sell copies of the Software, and to permit persons to whom the Software is
9
+ # furnished to do so, subject to the following conditions:
10
+ #
11
+ # The above copyright notice and this permission notice shall be included in
12
+ # all copies or substantial portions of the Software.
13
+ #
14
+ # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15
+ # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16
+ # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
17
+ # THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
18
+ # IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
19
+ # CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
20
+
21
+ require 'time'
22
+
23
+ module Rack
24
+ class Date
25
+
26
+ def initialize(app, no_cache_control = nil, cache_control = nil)
27
+ @app = app
28
+ end
29
+
30
+ def call(env)
31
+ status, headers, body = @app.call(env)
32
+ headers['Date'] = Time.new.httpdate if not headers['Date']
33
+ [status, headers, body]
34
+ end
35
+
36
+ end
37
+ end
38
+
@@ -30,11 +30,10 @@ module Rack
30
30
  # used when Etag is absent and a directive when it is present. The first
31
31
  # defaults to nil, while the second defaults to "max-age=0, privaute, must-revalidate"
32
32
  class ETag
33
- DEFAULT_CACHE_CONTROL = "max-age=0, private, must-revalidate".freeze
34
33
 
35
- def initialize(app, no_cache_control = nil, cache_control = DEFAULT_CACHE_CONTROL)
34
+ def initialize(app, no_cache_control = nil, cache_control = nil)
36
35
  @app = app
37
- @cache_control = cache_control
36
+ @cache_control = cache_control || "max-age=0, private, must-revalidate"
38
37
  @no_cache_control = no_cache_control
39
38
  end
40
39
 
@@ -36,46 +36,68 @@ module Rack
36
36
  #
37
37
  # All HTTP methods are supported, in case of POST they will be passed as a
38
38
  # regular <form> parameters.
39
-
39
+
40
40
  def call(env)
41
41
  # Copy PATH_INFO to REQUEST_URI if Rack::Test
42
42
  env['REQUEST_URI'] = env['PATH_INFO'] if env['rack.test']
43
+ env['REQUEST_PATH'] = env['PATH_INFO'] if env['rack.test']
43
44
 
44
45
  # Split URI to components and then extract ;var=value pairs
45
46
  uri_components = env['REQUEST_URI'].split('/')
46
47
  matrix_params = {}
47
48
  uri_components.each do |component|
48
- sub_components, value = component.split(/\;(\w+)\=/), nil
49
- next unless sub_components.first # Skip subcomponent if it's empty (usually /)
50
- while param=sub_components.pop do
51
- if value
52
- matrix_params[sub_components.first] ||= {}
53
- matrix_params[sub_components.first].merge!(
54
- param => value
55
- )
56
- value=nil
57
- next
58
- else
59
- value = param
60
- end
61
- end
49
+ sub_components, value = component.split(/\;(\w+)\=/), nil
50
+ next unless sub_components.first # Skip subcomponent if it's empty (usually /)
51
+ while param=sub_components.pop do
52
+ if value
53
+ matrix_params[sub_components.first] ||= {}
54
+ matrix_params[sub_components.first].merge!(
55
+ param => value
56
+ )
57
+ value=nil
58
+ next
59
+ else
60
+ value = param.gsub(/\?.*$/, '')
61
+ end
62
+ end
62
63
  end
63
64
 
64
- # If request method is POST, simply include matrix params in form_hash
65
- env['rack.request.form_hash'].merge!(matrix_params) if env['rack.request.form_hash']
65
+ # Two things need to happen to make matrix params work:
66
+ # (1) the parameters need to be appended to the 'normal' params
67
+ # for the request. 'Normal' really depends on the content
68
+ # type of the request, which does not seem accessible from
69
+ # Middleware, so we use the existence of
70
+ # rack.request.form_hash in the environment to distinguish
71
+ # between basic and application/x-www-form-urlencoded
72
+ # requests
73
+ # (2) the parameters need to be stripped from the appropriate
74
+ # path related env variables, so that request dispatching
75
+ # does not trip over them
76
+
77
+ # (1) Rewrite current path by stripping all matrix params from it
78
+ if env['REQUEST_PATH'] == '/'
79
+ env['REQUEST_URI'] = env['REQUEST_PATH']
80
+ env['REQUEST_PATH'] = env['PATH_INFO']
81
+ end
82
+ env['REQUEST_PATH'] = env['REQUEST_PATH'].gsub(/;([^\/]*)/, '').gsub(/\?(.*)$/, '')
83
+ env['PATH_INFO'] = env['REQUEST_PATH']
66
84
 
67
- # For other methods it's a way complicated ;-)
68
- if env['REQUEST_METHOD']!='POST' and not matrix_params.keys.empty?
69
- # Rewrite current path and query string and strip all matrix params from it
70
- env['REQUEST_PATH'], env['PATH_INFO'] = env['REQUEST_URI'].gsub(/;([^\/]*)/, '').gsub(/\?(.*)$/, '')
71
- env['PATH_INFO'] = env['REQUEST_PATH']
72
- env['QUERY_STRING'].gsub!(/;([^\/]*)/, '')
73
- new_params = matrix_params.collect do |component, params|
74
- params.collect { |k,v| "#{component}[#{k}]=#{CGI::escape(v.to_s)}" }
75
- end.flatten
76
- # Add matrix params as a regular GET params
77
- env['QUERY_STRING'] += '&' if not env['QUERY_STRING'].empty?
78
- env['QUERY_STRING'] += "#{new_params.join('&')}"
85
+ # (2) Append the matrix params to the 'normal' request params
86
+ # FIXME: Make this work for multipart/form-data
87
+ if env['rack.request.form_hash']
88
+ # application/x-www-form-urlencoded, most likely a POST
89
+ env['rack.request.form_hash'].merge!(matrix_params)
90
+ else
91
+ # For other methods it's more complicated
92
+ if env['REQUEST_METHOD']!='POST' and not matrix_params.keys.empty?
93
+ env['QUERY_STRING'].gsub!(/;([^\/]*)/, '')
94
+ new_params = matrix_params.collect do |component, params|
95
+ params.collect { |k,v| "#{component}[#{k}]=#{CGI::escape(v.to_s)}" }
96
+ end.flatten
97
+ # Add matrix params as a regular GET params
98
+ env['QUERY_STRING'] += '&' if not env['QUERY_STRING'].empty?
99
+ env['QUERY_STRING'] += "#{new_params.join('&')}"
100
+ end
79
101
  end
80
102
  @app.call(env)
81
103
  end
@@ -39,7 +39,7 @@ module Rack
39
39
  if !headers.has_key?(@header_name)
40
40
  headers[@header_name] = "%0.6f" % request_time
41
41
  end
42
-
42
+
43
43
  [status, headers, body]
44
44
  end
45
45
  end
@@ -0,0 +1,86 @@
1
+ require 'syslog'
2
+ require 'lib/sinatra/body_proxy'
3
+
4
+ class SyslogFile < File
5
+
6
+ def initialize
7
+ @log = Syslog.open($0, Syslog::LOG_PID | Syslog::LOG_LOCAL5)
8
+ end
9
+
10
+ def write(string)
11
+ @log.warning(string) if string.strip.length > 0
12
+ return string.chars.count
13
+ end
14
+
15
+ def info(msg)
16
+ @log.info(msg)
17
+ end
18
+
19
+ def err(msg)
20
+ @log.err(msg)
21
+ end
22
+
23
+ alias :warning :err
24
+
25
+ end
26
+
27
+ # Code bellow was originaly copied from Rack::CommonLogger
28
+ # https://raw.github.com/rack/rack/master/lib/rack/commonlogger.rb
29
+
30
+ module Rack
31
+ # Rack::CommonLogger forwards every request to an +app+ given, and
32
+ # logs a line in the Apache common log format to the +logger+, or
33
+ # rack.errors by default.
34
+ class SyslogLogger
35
+
36
+ # Common Log Format: http://httpd.apache.org/docs/1.3/logs.html#common
37
+ # lilith.local - - [07/Aug/2006 23:58:02] "GET / HTTP/1.1" 500 -
38
+ # %{%s - %s [%s] "%s %s%s %s" %d %s\n} %
39
+ FORMAT = %{%s - %s [%s] "%s %s%s %s" %d %s %0.4f\n}
40
+
41
+ def initialize(app, logger=nil)
42
+ @app = app
43
+ @logger = logger || $stdout
44
+ end
45
+
46
+ def call(env)
47
+ began_at = Time.now
48
+ status, header, body = @app.call(env)
49
+ header = Utils::HeaderHash.new(header)
50
+ body = Rack::BodyProxy.new(body) { log(env, status, header, began_at) }
51
+ [status, header, body]
52
+ end
53
+
54
+ private
55
+
56
+ def log(env, status, header, began_at)
57
+ now = Time.now
58
+ length = extract_content_length(header)
59
+
60
+ if status.to_s =~ /5(\d{2})/
61
+ method = :err
62
+ else
63
+ method = :info
64
+ end
65
+
66
+ logger = @logger || env['rack.errors']
67
+ logger.send(method, FORMAT % [
68
+ env['HTTP_X_FORWARDED_FOR'] || env["REMOTE_ADDR"] || "-",
69
+ env["REMOTE_USER"] || "-",
70
+ now.strftime("%d/%b/%Y %H:%M:%S"),
71
+ env["REQUEST_METHOD"],
72
+ env["PATH_INFO"],
73
+ env["QUERY_STRING"].empty? ? "" : "?"+env["QUERY_STRING"],
74
+ env["HTTP_VERSION"],
75
+ status.to_s[0..3],
76
+ length,
77
+ now - began_at ])
78
+ end
79
+
80
+ def extract_content_length(headers)
81
+ value = headers['Content-Length'] or return '-'
82
+ value.to_s == '0' ? '-' : value
83
+ end
84
+ end
85
+ end
86
+
@@ -28,6 +28,19 @@ require 'uri'
28
28
 
29
29
  module Sinatra
30
30
  module UrlForHelper
31
+
32
+ DEFAULT_URI_PREFIX = "/api"
33
+
34
+ def api_url_for(url_fragment, mode=:path_only)
35
+ matrix_params = ''
36
+ if request.params['api']
37
+ matrix_params += ";provider=%s" % request.params['api']['provider'] if request.params['api']['provider']
38
+ matrix_params += ";driver=%s" % request.params['api']['driver'] if request.params['api']['driver']
39
+ end
40
+ url_fragment = "/#{url_fragment}" unless url_fragment =~ /^\// # There is no need to prefix URI with '/'
41
+ url_for "#{DEFAULT_URI_PREFIX}#{matrix_params}#{url_fragment}", mode
42
+ end
43
+
31
44
  # Construct a link to +url_fragment+, which should be given relative to
32
45
  # the base of this Sinatra app. The mode should be either
33
46
  # <code>:path_only</code>, which will generate an absolute path within
@@ -70,7 +83,7 @@ module Sinatra
70
83
  end
71
84
 
72
85
  def root_url
73
- url_for '/'
86
+ DEFAULT_URI_PREFIX
74
87
  end
75
88
  end
76
89
 
Binary file
Binary file
Binary file
Binary file
Binary file