uwa 0.4 → 0.5

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.
data/lib/uwa/config.rb CHANGED
@@ -1,6 +1,6 @@
1
1
  module UWA
2
2
  NAME = 'UWA'
3
- VERSION = '0.4'
3
+ VERSION = '0.5'
4
4
  DESC = 'Widget server for UWA specs by Netvibes (http://dev.netvibes.com/doc/universal_widget_api)'
5
5
  AUTHOR = 'Florent Solt'
6
6
  EMAIL = 'florent@solt.biz'
data/lib/uwa/handler.rb CHANGED
@@ -30,85 +30,20 @@ class Handler < Mongrel::HttpHandler
30
30
  def process(req,res)
31
31
  @request = req
32
32
  @response = res
33
- UWA::Server.log(@request.params['REQUEST_METHOD'], @request.params['REQUEST_URI'])
34
- @query = query_string(req.params['QUERY_STRING'])
35
- UWA::Server.log(:QUERY, @query.inspect)
36
-
37
- method = @request.params['PATH_INFO'].split('/')[1]
38
-
39
- if method.nil?
40
- @response.start(200) do |head, out|
41
- head["Content-Type"] = "text/html"
42
- xml = Builder::XmlMarkup.new(:indent => 4, :target => out)
43
- xml.instruct!
44
- xml.declare! :DOCTYPE, :html, :PUBLIC,
45
- '-//W3C//DTD XHTML 1.0 Strict//EN',
46
- 'http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd'
47
- xml.html(:xmlns => 'http://www.w3.org/1999/xhtml',
48
- 'xmlns:widget' => 'http://www.netvibes.com/ns/') do |xml|
49
- xml.head do |xml|
50
- xml.meta(:name => 'author', :content => @author)
51
- xml.meta(:name => 'description', :content => @description)
52
- xml.meta(:name => 'apiVersion', :content => @apiVersion)
53
- xml.meta(:name => 'inline', :content => @inline.to_s)
54
- xml.meta(:name => 'debugMode', :content => @debugMode.to_s)
55
- xml.meta(:name => 'keywords', :content => @keywords)
56
- xml.meta(:name => 'autoRefresh', :content => @autoRefresh) unless @autoRefresh.nil?
57
- xml.link(:rel => :stylesheet, :type => 'text/css',
58
- :href => 'http://www.netvibes.com/themes/uwa/style.css')
59
- xml.script("", :type => 'text/javascript',
60
- :src => 'http://www.netvibes.com/js/UWA/load.js.php?env=Standalone')
61
- xml.tag!('widget:preferences') do |xml|
62
- @preferences.each do |pref|
63
- xml.preference(pref)
64
- end
65
- end
66
- xml.title(@title)
67
- xml.link(:rel => :icon, :type => 'image/png', :href => @icon)
68
- css.each { |c| xml.style("\n" + c, :type => 'text/css') }
69
- xml.script(:type => 'text/javascript') do |xml|
70
- url = 'http://' + req.params['HTTP_HOST'] + req.params['SCRIPT_NAME']
71
- xml << "widget.remoteUrl = '#{url}/'\n"
72
- ['Text', 'Json', 'Xml', 'Feed'].each do |m|
73
- xml << "widget.remote#{m} = function(uri, cb) {
74
- UWA.Data.get#{m}(widget.remoteUrl + uri, cb); };\n"
75
- end
76
- script.each do |s|
77
- xml << "\n#{s}\n"
78
- end
79
- xml << "if (document.location && (document.location.hostname == 'localhost'
80
- || document.location.href.match('^#{url}'))) {
81
- UWA.proxies.ajax = '/proxy';
82
- UWA.Data.useJsonRequest = false;
83
- }\n"
84
- end
85
- end
86
- xml.body do |xml|
87
- body xml
88
- end
89
- end
90
- xml.target!
91
- end
92
- else
93
- if method == 'ressource'
94
- file = @request.params['PATH_INFO'].gsub(/\.\./, '').split('/')[2..-1].join($/)
95
- file = File.join(@base, 'ressources', file)
96
- send_file(file)
97
- elsif self.respond_to?(method.to_sym)
98
- begin
99
- @response.header["Content-Type"] = "text/html"
100
- @response.status = 200
101
- self.send(method.to_sym)
102
- @response.finished
103
- rescue Exception
104
- UWA::Server.log(:error, "#{$!.message} <#{$!.class.name}>")
105
- UWA::Server.log(:error, $!.backtrace)
106
- end
33
+ @tempfiles = []
34
+ begin
35
+ UWA::Server.log(@request.params['REQUEST_METHOD'], @request.params['REQUEST_URI'])
36
+ method = @request.params['PATH_INFO'].split('/')[1]
37
+ UWA::Server.log(:method, method.inspect)
38
+ parse_query
39
+ UWA::Server.log(:query, @query.inspect)
40
+ if method.nil?
41
+ index
107
42
  else
108
- @response.start(404) do |head, out|
109
- out.write("Method #{method.inspect} not found")
110
- end
43
+ ajax(method.to_sym)
111
44
  end
45
+ ensure
46
+ @tempfiles.each { |f| f.unlink }
112
47
  end
113
48
  end
114
49
 
@@ -118,7 +53,7 @@ class Handler < Mongrel::HttpHandler
118
53
  @response.body.write(buf)
119
54
  end
120
55
 
121
- def send_file(file, content_type = nil)
56
+ def send_file(file, content_type = 'application/octet-stream')
122
57
  if File.exists?(file)
123
58
  file_status = File.stat(file)
124
59
  @response.status = 200
@@ -126,6 +61,7 @@ class Handler < Mongrel::HttpHandler
126
61
  @response.header[Mongrel::Const::ETAG] = Mongrel::Const::ETAG_FORMAT %
127
62
  [file_status.mtime.to_i, file_status.size, file_status.ino]
128
63
  @response.header[Mongrel::Const::CONTENT_TYPE] = content_type unless content_type.nil?
64
+ @response.header['Content-disposition'] = "attachment; filename=\"#{File.basename(file)}\""
129
65
  @response.send_status(file_status.size)
130
66
  @response.send_header
131
67
  @response.send_file(file)
@@ -154,12 +90,165 @@ class Handler < Mongrel::HttpHandler
154
90
  xml << 'Loading...'
155
91
  end
156
92
 
157
- def query_string(req)
158
- query = {}
159
- CGI::parse(req.to_s).each do |k,v|
160
- query[k] = v.first if v.size <= 1
93
+ private
94
+
95
+ MULTIPART_REGEXP = /\Amultipart\/form-data.*boundary=\"?([^\";,]+)/n.freeze
96
+ NAME_REGEX = /Content-Disposition:.* name="?([^\";]*)"?/ni.freeze
97
+ CONTENT_TYPE_REGEX = /Content-Type: (.*)\r\n/ni.freeze
98
+ FILENAME_REGEX = /Content-Disposition:.* filename="?([^\";]*)"?/ni.freeze
99
+ CRLF = "\r\n".freeze
100
+ EOL = CRLF
101
+
102
+ # Inspired bu controller_mixin.rb from the Merb project
103
+ def parse_query
104
+ @query = Mongrel::HttpRequest.query_parse(@request.params['QUERY_STRING'])
105
+ if @request.params['REQUEST_METHOD'] =~ /post/i and @request.params['CONTENT_TYPE'] =~ MULTIPART_REGEXP
106
+ boundary = "--#{$1}"
107
+ buf = ""
108
+ content_length = @request.params['CONTENT_LENGTH'].to_i
109
+ boundary_size = boundary.size + EOL.size
110
+ bufsize = 16384
111
+ content_length -= boundary_size
112
+ status = @request.body.read(boundary_size)
113
+ raise EOFError, "bad content body" unless status == boundary + EOL
114
+ rx = /(?:#{EOL})?#{Regexp.quote(boundary)}(#{EOL}|--)/
115
+
116
+ loop do
117
+ head = nil
118
+ body = ''
119
+ filename = content_type = name = nil
120
+
121
+ until head && buf =~ rx
122
+ if !head && i = buf.index("\r\n\r\n")
123
+ head = buf.slice!(0, i+2) # First \r\n
124
+ buf.slice!(0, 2) # Second \r\n
125
+
126
+ filename = head[FILENAME_REGEX, 1]
127
+ content_type = head[CONTENT_TYPE_REGEX, 1]
128
+ name = head[NAME_REGEX, 1]
129
+
130
+ if filename
131
+ body = Tempfile.new(:uwa)
132
+ body.binmode if defined? body.binmode
133
+ end
134
+ next
135
+ end
136
+
137
+ # Save the read body part.
138
+ if head && (boundary_size+4 < buf.size)
139
+ body << buf.slice!(0, buf.size - (boundary_size+4))
140
+ end
141
+
142
+ c = @request.body.read(bufsize < content_length ? bufsize : content_length)
143
+ raise EOFError, "bad content body" if c.nil? || c.empty?
144
+ buf << c
145
+ content_length -= c.size
146
+ end
147
+
148
+ # Save the rest.
149
+ if i = buf.index(rx)
150
+ body << buf.slice!(0, i)
151
+ buf.slice!(0, boundary_size+2)
152
+
153
+ content_length = -1 if $1 == "--"
154
+ end
155
+
156
+ if filename
157
+ body.rewind
158
+ data = {'filename' => filename, 'type' => content_type, 'tempfile' => body}
159
+ @tempfiles << body
160
+ else
161
+ data = body
162
+ end
163
+ if @query[name].nil?
164
+ @query[name] = data
165
+ else
166
+ if not @query[name].is_a? Array
167
+ @query[name] = [@query[name]]
168
+ end
169
+ @query[name] << data
170
+ end
171
+ break if buf.empty? || content_length == -1
172
+ end
173
+ end
174
+ end
175
+
176
+ def index
177
+ @response.start(200) do |head, out|
178
+ head["Content-Type"] = "text/html"
179
+ xml = Builder::XmlMarkup.new(:indent => 4, :target => out)
180
+ xml.instruct!
181
+ xml.declare! :DOCTYPE, :html, :PUBLIC,
182
+ '-//W3C//DTD XHTML 1.0 Strict//EN',
183
+ 'http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd'
184
+ xml.html(:xmlns => 'http://www.w3.org/1999/xhtml',
185
+ 'xmlns:widget' => 'http://www.netvibes.com/ns/') do |xml|
186
+ xml.head do |xml|
187
+ xml.meta(:name => 'author', :content => @author)
188
+ xml.meta(:name => 'description', :content => @description)
189
+ xml.meta(:name => 'apiVersion', :content => @apiVersion)
190
+ xml.meta(:name => 'inline', :content => @inline.to_s)
191
+ xml.meta(:name => 'debugMode', :content => @debugMode.to_s)
192
+ xml.meta(:name => 'keywords', :content => @keywords)
193
+ xml.meta(:name => 'autoRefresh', :content => @autoRefresh) unless @autoRefresh.nil?
194
+ xml.link(:rel => :stylesheet, :type => 'text/css',
195
+ :href => 'http://www.netvibes.com/themes/uwa/style.css')
196
+ xml.script("", :type => 'text/javascript',
197
+ :src => 'http://www.netvibes.com/js/UWA/load.js.php?env=Standalone')
198
+ xml.tag!('widget:preferences') do |xml|
199
+ @preferences.each do |pref|
200
+ xml.preference(pref)
201
+ end
202
+ end
203
+ xml.title(@title)
204
+ xml.link(:rel => :icon, :type => 'image/png', :href => @icon)
205
+ css.each { |c| xml.style("\n" + c, :type => 'text/css') }
206
+ xml.script(:type => 'text/javascript') do |xml|
207
+ url = 'http://' + @request.params['HTTP_HOST'] + @request.params['SCRIPT_NAME']
208
+ xml << "widget.remoteUrl = '#{url}/'\n"
209
+ ['Text', 'Json', 'Xml', 'Feed'].each do |m|
210
+ xml << "widget.remote#{m} = function(uri, cb) {
211
+ UWA.Data.get#{m}(widget.remoteUrl + uri, cb); };\n"
212
+ end
213
+ script.each do |s|
214
+ xml << "\n#{s}\n"
215
+ end
216
+ xml << "if (document.location && (document.location.hostname == 'localhost'
217
+ || document.location.href.match('^#{url}'))) {
218
+ UWA.proxies.ajax = '/proxy';
219
+ UWA.Data.useJsonRequest = false;
220
+ }\n"
221
+ end
222
+ end
223
+ xml.body do |xml|
224
+ body xml
225
+ end
226
+ end
227
+ xml.target!
228
+ end
229
+ end
230
+
231
+ def ajax(method)
232
+ if method == :resource
233
+ file = @request.params['PATH_INFO'].gsub(/\.\./, '').split('/')[2..-1].join($/)
234
+ file = File.join(@base, 'resources', file)
235
+ send_file(file)
236
+ elsif self.respond_to?(method)
237
+ begin
238
+ @response.header["Content-Type"] = "text/html"
239
+ @response.status = 200
240
+ self.send(method)
241
+ @response.finished
242
+ rescue Exception
243
+ UWA::Server.log(:error, "#{$!.message} <#{$!.class.name}>")
244
+ UWA::Server.log(:error, $!.backtrace)
245
+ end
246
+ else
247
+ @response.start(404) do |head, out|
248
+ out.write("Method #{method.inspect} not found")
249
+ end
161
250
  end
162
- query
163
251
  end
252
+
164
253
  end
165
254
  end
data/lib/uwa/plugin.rb CHANGED
@@ -15,6 +15,8 @@ class Plugin
15
15
  end
16
16
 
17
17
  def load
18
+ return @list unless @list.empty?
19
+
18
20
  sdir = File.join(Gem.dir, "specifications")
19
21
  gems = Gem::SourceIndex.from_installed_gems(sdir)
20
22
  needs = {"uwa" => false}
@@ -31,12 +33,13 @@ class Plugin
31
33
  file = File.join(gem_dir, "lib", gem.name, "widget.rb")
32
34
  before = UWA::Widget.constants rescue []
33
35
  require file
36
+ UWA::Server.log(:info, "Load plugin #{gem.name.inspect} v#{gem.version}")
34
37
  after = UWA::Widget.constants
35
38
  @list[gem.name] = {
36
39
  :base => gem_dir,
37
40
  :class => UWA::Widget.const_get((after - before).first.to_sym),
38
- :script => Dir[File.join(gem_dir, 'ressources', '*.js')],
39
- :css => Dir[File.join(gem_dir, 'ressources', '*.css')]
41
+ :script => Dir[File.join(gem_dir, 'resources', '*.js')],
42
+ :css => Dir[File.join(gem_dir, 'resources', '*.css')]
40
43
  }
41
44
  end
42
45
  end
data/lib/uwa/server.rb CHANGED
@@ -16,38 +16,50 @@ class Server
16
16
  @debug = true
17
17
  @reload = true
18
18
  @widgets = []
19
- @plugins = UWA::Plugin.load
19
+ @mongrel = nil
20
+ @plugins = []
20
21
  end
21
22
 
22
23
  def <<(config)
24
+ @plugins = UWA::Plugin.load if @plugins.empty?
25
+
23
26
  begin
24
27
  @widgets << @plugins[config[:name]].merge(config)
25
28
  rescue
26
- log(:warning, "Unable to register #{config[:name].inspect} at #{config[:path].inspect}")
29
+ log(:warning, "Unable to configure #{config[:name].inspect} at #{config[:path].inspect}")
27
30
  else
28
- log(:info, "Register #{config[:name].inspect} at #{config[:path].inspect}")
31
+ log(:info, "Configure #{config[:name].inspect} at #{config[:path].inspect}")
29
32
  end
30
33
  end
31
34
 
32
35
  def run
33
- m = nil
34
36
  begin
35
37
  $mongrel_debug_client = @debug
36
- m = Mongrel::HttpServer.new(@host, @port) if m.nil?
38
+ @mongrel = Mongrel::HttpServer.new(@host, @port) if @mongrel.nil?
37
39
  @widgets.each do |widget|
38
- object = widget[:class].new
39
- object.base = widget[:base]
40
- object.script = widget[:script]
41
- object.css = widget[:css]
42
- widget[:params].to_a.each do |name, value|
43
- object.instance_variable_set(('@' + name.to_s).to_sym, value)
40
+ unless @mongrel.classifier.uris.include?(widget[:path])
41
+ object = widget[:class].new
42
+ object.base = widget[:base]
43
+ object.script = widget[:script]
44
+ object.css = widget[:css]
45
+ widget[:params].to_a.each do |name, value|
46
+ object.instance_variable_set(('@' + name.to_s).to_sym, value)
47
+ end
48
+ @mongrel.register(widget[:path], object)
49
+ log(:info, "Register #{widget[:name].inspect} at #{widget[:path].inspect}")
44
50
  end
45
- m.register(widget[:path], object)
46
51
  end
47
- m.register('/proxy', UWA::Proxy.new)
48
- m.run.join
49
- rescue
50
- m.graceful_shutdown unless m.nil?
52
+ unless @mongrel.classifier.uris.include?('/proxy')
53
+ @mongrel.register('/proxy', UWA::Proxy.new)
54
+ log(:info, "Proxy at \"/proxy\"")
55
+ end
56
+ log(:info, "Ready to serve")
57
+ @mongrel.run.join
58
+ rescue Interrupt
59
+ # Do nothing
60
+ log(:info, "Shutdown")
61
+ rescue Exception
62
+ @mongrel.graceful_shutdown unless @mongrel.nil?
51
63
  log :error , $!.message
52
64
  log :error, $!.backtrace
53
65
  log :error, "Retrying in 5 seconds..."
metadata CHANGED
@@ -3,8 +3,8 @@ rubygems_version: 0.9.2
3
3
  specification_version: 1
4
4
  name: uwa
5
5
  version: !ruby/object:Gem::Version
6
- version: "0.4"
7
- date: 2007-04-02 00:00:00 +02:00
6
+ version: "0.5"
7
+ date: 2007-04-03 00:00:00 +02:00
8
8
  summary: Widget server for UWA specs by Netvibes (http://dev.netvibes.com/doc/universal_widget_api)
9
9
  require_paths:
10
10
  - lib