uwa 0.4 → 0.5

Sign up to get free protection for your applications and to get access to all the features.
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