murlsh 0.11.0 → 1.0.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (56) hide show
  1. data/.htaccess +2 -0
  2. data/README.textile +3 -33
  3. data/Rakefile +12 -5
  4. data/VERSION +1 -1
  5. data/config.ru +10 -4
  6. data/config.yaml +6 -12
  7. data/lib/murlsh/dispatch.rb +0 -6
  8. data/lib/murlsh/img_store.rb +36 -0
  9. data/lib/murlsh/markup.rb +0 -1
  10. data/lib/murlsh/plugin.rb +2 -6
  11. data/lib/murlsh/uri_ask.rb +66 -22
  12. data/lib/murlsh/url.rb +0 -18
  13. data/lib/murlsh/url_body.rb +15 -23
  14. data/lib/murlsh/url_server.rb +5 -5
  15. data/murlsh.gemspec +44 -19
  16. data/plugins/add_post_50_update_feed.rb +17 -3
  17. data/plugins/add_post_50_update_podcast.rb +46 -0
  18. data/plugins/add_post_50_update_rss.rb +18 -2
  19. data/plugins/add_post_60_notify_hubs.rb +3 -1
  20. data/plugins/add_pre_40_convert_mobile.rb +30 -0
  21. data/plugins/add_pre_50_lookup_content_type_title.rb +11 -4
  22. data/plugins/add_pre_60_flickr.rb +38 -0
  23. data/plugins/add_pre_60_github_title.rb +5 -1
  24. data/plugins/add_pre_60_google_code_title.rb +5 -2
  25. data/plugins/add_pre_60_imageshack.rb +31 -0
  26. data/plugins/add_pre_60_imgur.rb +32 -0
  27. data/plugins/add_pre_60_s3_image.rb +34 -0
  28. data/plugins/add_pre_60_twitter.rb +35 -0
  29. data/plugins/add_pre_60_vimeo.rb +35 -0
  30. data/plugins/add_pre_60_youtube.rb +31 -0
  31. data/plugins/html_parse_50_hpricot.rb +2 -0
  32. data/plugins/url_display_add_45_mp3.rb +30 -0
  33. data/plugins/url_display_add_50_hostrec.rb +38 -0
  34. data/plugins/url_display_add_55_content_type.rb +27 -0
  35. data/plugins/url_display_add_60_via.rb +52 -0
  36. data/plugins/url_display_add_65_time.rb +22 -0
  37. data/public/css/jquery.jgrowl.css +0 -3
  38. data/public/css/screen.css +0 -18
  39. data/public/img/thumb/README +0 -0
  40. data/public/js/jquery-1.4.3.min.js +166 -0
  41. data/public/js/js.js +62 -234
  42. data/public/js/twitter-text-1.0.3.js +538 -0
  43. data/spec/img_store_spec.rb +53 -0
  44. data/spec/uri_ask_spec.rb +14 -4
  45. metadata +139 -37
  46. data/lib/murlsh/flickr_server.rb +0 -55
  47. data/lib/murlsh/twitter_server.rb +0 -45
  48. data/lib/murlsh/unwrap_jsonp.rb +0 -15
  49. data/lib/murlsh/xhtml_response.rb +0 -20
  50. data/plugins/hostrec_50_redundant.rb +0 -14
  51. data/plugins/hostrec_60_skip.rb +0 -24
  52. data/plugins/time_50_ago.rb +0 -16
  53. data/plugins/via_50_domain.rb +0 -36
  54. data/public/js/jquery-1.4.2.min.js +0 -154
  55. data/spec/unwrap_json_spec.rb +0 -21
  56. data/spec/xhtml_response_spec.rb +0 -112
data/.htaccess CHANGED
@@ -1,6 +1,8 @@
1
1
  Options -Indexes
2
2
 
3
+ AddOutputFilterByType DEFLATE application/atom+xml
3
4
  AddOutputFilterByType DEFLATE application/javascript
5
+ AddOutputFilterByType DEFLATE application/rss+xml
4
6
  AddOutputFilterByType DEFLATE application/xhtml+xml
5
7
  AddOutputFilterByType DEFLATE application/xml
6
8
  AddOutputFilterByType DEFLATE text/css
data/README.textile CHANGED
@@ -1,7 +1,7 @@
1
1
  Site for sharing and archiving links.
2
2
 
3
3
  * looks up url titles
4
- * adds thumbnails for and jGrowls embedded versions of Flickr, Imageshack, Vimeo and YouTube urls
4
+ * adds thumbnails for and jGrowls embedded versions of Imageshack, Vimeo and YouTube urls
5
5
  * converts Twitter status urls to their full text and adds user thumbnail
6
6
  * generates Atom and RSS feeds
7
7
  * regex search
@@ -12,10 +12,6 @@ Site for sharing and archiving links.
12
12
  * rack interface
13
13
  * Gravatar support
14
14
 
15
- !http://static.mmb.s3.amazonaws.com/murlsh_screenshot.jpg!
16
-
17
- !http://static.mmb.s3.amazonaws.com/murlsh_iphone_screenshot.jpg!
18
-
19
15
  See "http://urls.matthewm.boedicker.org/":http://urls.matthewm.boedicker.org/ for example.
20
16
 
21
17
  h1. Installation
@@ -59,11 +55,9 @@ Plugin hooks
59
55
 
60
56
  |Hook|Description|run() arguments|Returns|
61
57
  |add_pre|called before a new url is saved|url, config hash|undefined|
62
- |add_post|called after a new url is saved|config hash|undefined|
63
- |hostrec|post process the domain that is shown after links|domain, url, title|text to display|
58
+ |add_post|called after a new url is saved|url, config hash|undefined|
64
59
  |html_parse|parse HTML using something like Hpricot or Nokogiri|parseable|parsed HTML, only first plugin is run (cannot be chained)|
65
- |time|convert the time of a post into a string for display|time|time display text|
66
- |via|convert a via url into a string for display|via url|via url display text|
60
+ |url_display_add|called to display additional information after urls|markup builder, url, config hash|undefined|
67
61
 
68
62
  h1. PubSubHubbub
69
63
 
@@ -84,33 +78,9 @@ subscribe_url is what gets put in the feed as link rel="hub"
84
78
 
85
79
  This will make updates to your feed show up in Google Reader instantly.
86
80
 
87
- h1. Thumbnail Locators
88
-
89
- If the url for a thumbnail image can be generated by regex search and replace
90
- on a posted url, a rule can be added to the configuration to automatically
91
- show a thumbnail image for it. The 'thumb_locators' config key is a hash
92
- of Javascript regex to Javascript replacement string (which can include
93
- captured groups). The hash key is wrapped in ^ and $ before compilation so
94
- it must match the entire url. The regex is compiled case-insensitive.
95
-
96
- For example:
97
-
98
- * Show the GitHub octocat Apple touch icon
99
- (http://github.com/apple-touch-icon.png) as a thumbnail for GitHub links
100
- * Show a friend's Gravatar for the thumbnails of links to his blog
101
-
102
- <pre>
103
- <code>
104
- thumb_locators:
105
- (http:\/\/github\.com\/).*: $1apple-touch-icon.png
106
- http:\/\/myfriend\.com\/.*: http://gravatar.com/xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx</code>
107
- </pre>
108
-
109
81
  h1. Design Goals
110
82
 
111
- * make site fast and very cacheable, caching wrapper around calls to third party JSON APIs
112
83
  * low effort required to add a url, get metadata programatically instead of requiring user to specify
113
- * heavy lifting on the client side
114
84
  * allow customization with config and plugins
115
85
  * full regex search for finding saved urls
116
86
  * simple security (no sessions, no cookies)
data/Rakefile CHANGED
@@ -81,8 +81,10 @@ namespace :db do
81
81
  email TEXT,
82
82
  name TEXT,
83
83
  title TEXT,
84
+ content_length INTEGER,
84
85
  content_type TEXT,
85
- via TEXT);
86
+ via TEXT,
87
+ thumbnail_url TEXT);
86
88
  ")
87
89
  end
88
90
 
@@ -190,8 +192,8 @@ end
190
192
 
191
193
  namespace :validate do
192
194
 
193
- desc 'Validate XHTML.'
194
- task :xhtml do
195
+ desc 'Validate HTML.'
196
+ task :html do
195
197
  check_url = config['root_url']
196
198
  print "validating #{check_url} : "
197
199
  result = validate(check_url)
@@ -340,17 +342,22 @@ begin
340
342
  activerecord 2.3.4
341
343
  bcrypt-ruby 2.1.2
342
344
  builder 2.1.2
345
+ flickraw 0.8.3
346
+ flog 2.5.0
343
347
  hpricot 0.8.1
344
348
  htmlentities 4.2.0
345
349
  json 1.2.3
346
350
  push-notify 0.1.0
347
351
  rack 1.0.0
348
352
  rack-cache 0.5.2
353
+ rack-rewrite 1.0.2
349
354
  rack-throttle 0.3.0
350
355
  sqlite3-ruby 1.2.1
351
- tinyatom 0.1.1
356
+ tinyatom 0.2.0
357
+ twitter 0.9.12
358
+ vimeo 1.2.2
352
359
  }.each_slice(2) { |g,v| gemspec.add_dependency(g, ">= #{v}") }
353
-
360
+ gemspec.add_dependency('rspec', '~> 1.3')
354
361
  end
355
362
  rescue LoadError
356
363
  puts "Jeweler not available. Install it with: gem install jeweler"
data/VERSION CHANGED
@@ -1 +1 @@
1
- 0.11.0
1
+ 1.0.0
data/config.ru CHANGED
@@ -4,6 +4,7 @@ $:.unshift(File.join(File.dirname(__FILE__), 'lib'))
4
4
  yaml
5
5
 
6
6
  rack/cache
7
+ rack/rewrite
7
8
  rack/throttle
8
9
 
9
10
  murlsh
@@ -25,11 +26,16 @@ use Murlsh::EtagAddEncoding
25
26
  use Rack::Deflater
26
27
  use Murlsh::FarFutureExpires, :patterns => %r{\.gen\.(css|js)$}
27
28
 
28
- feed_path = URI.join(config.fetch('root_url'), config.fetch('feed_file')).path
29
- use Murlsh::MustRevalidate, :patterns => %r{^#{Regexp.escape(feed_path)}$}
29
+ feed_url = URI.join(config.fetch('root_url'), config.fetch('feed_file'))
30
+ use Murlsh::MustRevalidate, :patterns => %r{^#{Regexp.escape(feed_url.path)}$}
30
31
 
31
- use Rack::Static, :urls => %w{/css /js /swf}, :root => 'public'
32
- use Rack::Static, :urls => %w{/atom.xml /rss.xml}
32
+ use Rack::Static, :urls => %w{/css /img /js /swf}, :root => 'public'
33
+ use Rack::Static, :urls => %w{/atom.atom /podcast.rss /rss.rss}
34
+
35
+ use Rack::Rewrite do
36
+ r301 '/atom.xml', feed_url.to_s
37
+ r301 '/rss.xml', URI.join(config.fetch('root_url'), 'rss.rss').to_s
38
+ end
33
39
 
34
40
  # use Rack::Lint
35
41
 
data/config.yaml CHANGED
@@ -2,18 +2,19 @@
2
2
  auth_file: murlsh_users
3
3
  cache_entitystore: file:tmp/cache/rack/body
4
4
  cache_metastore: file:tmp/cache/rack/meta
5
- config_js:
6
- - thumb_locators
5
+ config_js: []
6
+
7
7
  css_files:
8
8
  - css/jquery.jgrowl.css
9
9
  - css/screen.css
10
10
  db_file: murlsh.db
11
- feed_file: atom.xml
11
+ feed_file: atom.atom
12
12
  flickr_api_key:
13
13
  gravatar_size: 32
14
14
  js_files:
15
- - js/jquery-1.4.2.min.js
15
+ - js/jquery-1.4.3.min.js
16
16
  - js/jquery.jgrowl_compressed.js
17
+ - js/twitter-text-1.0.3.js
17
18
  - js/js.js
18
19
  meta_tag_description: URLs found interesting by Matthew M. Boedicker
19
20
  meta_tag_verify-v1:
@@ -25,11 +26,4 @@ pubsubhubbub_hubs: []
25
26
 
26
27
  root_url: http://urls.matthewm.boedicker.org/
27
28
  show_names: true
28
- thumb_locators:
29
- (http:\/\/(cgi\.)?ebay\.(com|co\.uk)\/).*: $1apple-touch-icon.png
30
- (http:\/\/blog\.makezine\.com\/).*: $1apple-touch-icon.png
31
- (http:\/\/en\.wikipedia\.org\/).*: $1apple-touch-icon.png
32
- (http:\/\/github\.com\/).*: $1apple-touch-icon.png
33
- (http:\/\/stackoverflow\.com\/).*: $1apple-touch-icon.png
34
- (http:\/\/www\.nytimes\.com\/).*: $1apple-touch-icon.png
35
- (http:\/\/www\.wired\.com\/).*: $1apple-touch-icon.png
29
+ user_agent: murlsh (http://github.com/mmb/murlsh)
@@ -22,8 +22,6 @@ module Murlsh
22
22
 
23
23
  url_server = Murlsh::UrlServer.new(@config, db)
24
24
  config_server = Murlsh::ConfigServer.new(@config)
25
- flickr_server = Murlsh::FlickrServer.new(@config)
26
- twitter_server = Murlsh::TwitterServer.new
27
25
 
28
26
  root_path = URI(@config.fetch('root_url')).path
29
27
 
@@ -33,10 +31,6 @@ module Murlsh
33
31
  [%r{^POST #{root_path}(url)?$}, url_server.method(:post)],
34
32
  [%r{^HEAD #{root_path}config$}, config_server.method(:head)],
35
33
  [%r{^GET #{root_path}config$}, config_server.method(:get)],
36
- [%r{^HEAD #{root_path}flickr$}, flickr_server.method(:head)],
37
- [%r{^GET #{root_path}flickr$}, flickr_server.method(:get)],
38
- [%r{^HEAD #{root_path}twitter/.+$}, twitter_server.method(:head)],
39
- [%r{^GET #{root_path}twitter/.+$}, twitter_server.method(:get)],
40
34
  ]
41
35
  end
42
36
 
@@ -0,0 +1,36 @@
1
+ %w{
2
+ cgi
3
+ open-uri
4
+ }.each { |m| require m }
5
+
6
+ module Murlsh
7
+
8
+ # Fetch images from urls and store them locally.
9
+ class ImgStore
10
+
11
+ def initialize(storage_dir, options={})
12
+ @storage_dir = storage_dir
13
+ @user_agent = options[:user_agent]
14
+ end
15
+
16
+ # Build headers to send with request.
17
+ def headers
18
+ result = {}
19
+ result['User-Agent'] = @user_agent if @user_agent
20
+ result
21
+ end
22
+
23
+ # Fetch an image from a url and store it locally.
24
+ def store(url)
25
+ local_file = CGI.escape(url)
26
+ local_path = File.join(storage_dir, local_file)
27
+ open(url, headers) do |fin|
28
+ open(local_path, 'w') { |fout| fout.write(fin.read) }
29
+ end
30
+ local_file
31
+ end
32
+
33
+ attr_reader :storage_dir
34
+ end
35
+
36
+ end
data/lib/murlsh/markup.rb CHANGED
@@ -53,7 +53,6 @@ module Murlsh
53
53
  attrs = {
54
54
  :href => "#{options[:prefix]}#{href}",
55
55
  :rel => 'stylesheet',
56
- :type => 'text/css',
57
56
  }
58
57
  attrs[:media] = options[:media] if options[:media]
59
58
  link(attrs)
data/lib/murlsh/plugin.rb CHANGED
@@ -7,14 +7,10 @@ module Murlsh
7
7
  # run arguments (url, config hash)
8
8
  # * add_post - called after a new url is saved
9
9
  # run arguments (config hash)
10
- # * hostrec - called to post process the domain that shows after links
11
- # run arguments (domain, url, title)
12
10
  # * html_parse - called to parse HTML using something like Hpricot or Nokogiri
13
11
  # run arguments (parseable)
14
- # * time - called to convert the time of a post into a string for display
15
- # run arguments (time)
16
- # * via - called to convert a via url into a string for display
17
- # run arguments (via url)
12
+ # * url_display_add - called to display additional information after urls
13
+ # run arguments (markup builder, url, config hash)
18
14
  class Plugin
19
15
 
20
16
  # Called when a plugin class inherits from this class (the way plugins
@@ -14,33 +14,19 @@ module Murlsh
14
14
  # URI mixin.
15
15
  module UriAsk
16
16
 
17
- # Get the content type.
17
+ # Get the content length.
18
18
  #
19
19
  # Options:
20
20
  # * :failproof - if true hide all exceptions and return empty string on failure
21
21
  # * :headers - hash of headers to send in request
22
- def content_type(options={})
23
- return @content_type if defined?(@content_type)
24
- options[:headers] = default_headers.merge(options.fetch(:headers, {}))
25
-
26
- content_type = ''
27
- Murlsh::failproof(options) do
28
- # try head first to save bandwidth
29
- http = Net::HTTP.new(host, port)
30
- http.use_ssl = (scheme == 'https')
31
-
32
- resp = http.request_head(path_query, options[:headers])
22
+ def content_length(options={}); header('content-length', options); end
33
23
 
34
- if Net::HTTPSuccess === resp
35
- content_type = resp['content-type']
36
- end
37
-
38
- if not content_type or content_type.empty?
39
- content_type = self.open(options[:headers]) { |f| f.content_type }
40
- end
41
- end
42
- @content_type = content_type
43
- end
24
+ # Get the content type.
25
+ #
26
+ # Options:
27
+ # * :failproof - if true hide all exceptions and return empty string on failure
28
+ # * :headers - hash of headers to send in request
29
+ def content_type(options={}); header('content-type', options); end
44
30
 
45
31
  # Get the HTML title.
46
32
  #
@@ -134,6 +120,64 @@ module Murlsh
134
120
  HTMLEntities.new.decode(Iconv.conv('utf-8', @charset, s))
135
121
  end
136
122
 
123
+ # Get the value of a response header.
124
+ #
125
+ # Options:
126
+ # * :failproof - if true hide all exceptions and return empty string on failure
127
+ # * :headers - hash of headers to send in request
128
+ def header(header_name, options={})
129
+ result = [*head_headers(options)[header_name]][0]
130
+ result = get_headers(options)[header_name] if !result or result.empty?
131
+ result || ''
132
+ end
133
+
134
+ # Get and cache response headers returned by HTTP HEAD for this URI.
135
+ #
136
+ # Return hash values are lists.
137
+ #
138
+ # Options:
139
+ # * :failproof - if true hide all exceptions and return empty hash on failure
140
+ # * :headers - hash of headers to send in request
141
+ def head_headers(options={})
142
+ return @head_headers if defined?(@head_headers)
143
+
144
+ request_headers = default_headers.merge(options.fetch(:headers, {}))
145
+
146
+ response_headers = {}
147
+ Murlsh::failproof(options) do
148
+ http = Net::HTTP.new(host, port)
149
+ http.use_ssl = (scheme == 'https')
150
+
151
+ resp = http.request_head(path_query, request_headers)
152
+
153
+ if Net::HTTPSuccess === resp
154
+ response_headers = resp.to_hash
155
+ end
156
+
157
+ end
158
+ @head_headers = response_headers
159
+ end
160
+
161
+ # Get and cache response headers returned by HTTP GET for this URI.
162
+ #
163
+ # Return hash values are single strings.
164
+ #
165
+ # Options:
166
+ # * :failproof - if true hide all exceptions and return empty hash on failure
167
+ # * :headers - hash of headers to send in request
168
+ def get_headers(options={})
169
+ return @get_headers if defined?(@get_headers)
170
+
171
+ request_headers = default_headers.merge(options.fetch(:headers, {}))
172
+
173
+ response_headers = {}
174
+ # use open-uri instead of Net::HTTP because it handles redirects
175
+ Murlsh::failproof(options) do
176
+ response_headers = self.open(request_headers) { |f| f.meta }
177
+ end
178
+ @get_headers = response_headers
179
+ end
180
+
137
181
  end
138
182
 
139
183
  end
data/lib/murlsh/url.rb CHANGED
@@ -31,24 +31,6 @@ module Murlsh
31
31
  email and name and email == other.email and name == other.name
32
32
  end
33
33
 
34
- # Return text showing what domain a link goes to.
35
- def hostrec
36
- domain = Murlsh::failproof { URI(url).domain }
37
-
38
- domain = Murlsh::Plugin.hooks('hostrec').inject(domain) {
39
- |result,plugin| plugin.run(result, url, title) }
40
-
41
- yield domain if domain
42
- end
43
-
44
- # Yield the url that the url came from.
45
- def viarec; Murlsh::failproof { yield URI(via) } if via; end
46
-
47
- # Return true if this url is an image.
48
- def is_image?
49
- %w{image/gif image/jpeg image/png}.include?(content_type)
50
- end
51
-
52
34
  end
53
35
 
54
36
  end
@@ -8,9 +8,10 @@ module Murlsh
8
8
  class UrlBody < Builder::XmlMarkup
9
9
  include Murlsh::Markup
10
10
 
11
- def initialize(config, db, req)
12
- @config, @db, @req, @q = config, db, req, req.params['q']
13
- super(:indent => @config['xhtml_indent'] || 0)
11
+ def initialize(config, db, req, content_type='text/html')
12
+ @config, @db, @req, @q, @content_type =
13
+ config, db, req, req.params['q'], content_type
14
+ super(:indent => @config['html_indent'] || 0)
14
15
  end
15
16
 
16
17
  # Fetch urls base on query string parameters.
@@ -33,14 +34,9 @@ module Murlsh
33
34
 
34
35
  # Url list page body builder.
35
36
  def each
36
- instruct! :xml
37
- declare! :DOCTYPE, :html, :PUBLIC, '-//W3C//DTD XHTML 1.1//EN',
38
- 'http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd'
39
-
40
- yield html(:xmlns => 'http://www.w3.org/1999/xhtml',
41
- :'xmlns:xsi' => 'http://www.w3.org/2001/XMLSchema-instance',
42
- :'xsi:schemaLocation' => 'http://www.w3.org/MarkUp/SCHEMA/xhtml11.xsd',
43
- :'xml:lang' => 'en') {
37
+ declare! :DOCTYPE, :html
38
+
39
+ yield html(:lang => 'en') {
44
40
  headd
45
41
  body {
46
42
  ul(:id => 'urls') {
@@ -59,22 +55,17 @@ module Murlsh
59
55
  @config.fetch('show_names', false) and mu.name
60
56
  end
61
57
 
58
+ if mu.thumbnail_url
59
+ murlsh_img(:src => mu.thumbnail_url,
60
+ :text => mu.title_stripped, :class => 'thumb')
61
+ end
62
+
62
63
  a(mu.title_stripped, :href => mu.url, :class => 'm')
63
64
 
64
- mu.hostrec do |hostrec|
65
- self.span(" [#{hostrec}]", :class => 'host')
66
- end
67
- mu.viarec do |via|
68
- display_via = Murlsh::Plugin.hooks('via').inject(
69
- via) { |result,plugin| plugin.run(result) }
70
- span(:class => 'via') {
71
- text!(' via '); a(display_via, :href => via)
72
- }
65
+ Murlsh::Plugin.hooks('url_display_add') do |p|
66
+ p.run(self, mu, @config)
73
67
  end
74
68
 
75
- display_time = Murlsh::Plugin.hooks('time').inject(
76
- mu.time) { |result,plugin| plugin.run(result) }
77
- span(", #{display_time}", :class => 'date') if display_time
78
69
  last = mu
79
70
  }
80
71
  end
@@ -94,6 +85,7 @@ module Murlsh
94
85
  def headd
95
86
  head {
96
87
  titlee
88
+ meta :'http-equiv' => 'Content-Type', :content => @content_type
97
89
  metas(@config.select { |k,v| k =~ /^meta_tag_/ and v }.
98
90
  map { |k,v| [k.sub('meta_tag_', ''), v] })
99
91
  css(@config['css_compressed'] || @config['css_files'])
@@ -20,16 +20,16 @@ module Murlsh
20
20
  # Respond to a GET request. Return a page of urls based on the query
21
21
  # string parameters.
22
22
  def get(req)
23
- resp = Murlsh::XhtmlResponse.new
23
+ last_db_update = File::Stat.new(@config['db_file']).mtime
24
24
 
25
- resp.set_content_type(req.env['HTTP_ACCEPT'], req.env['HTTP_USER_AGENT'])
25
+ resp = Rack::Response.new
26
26
 
27
- last_db_update = File::Stat.new(@config['db_file']).mtime
28
27
  resp['Cache-Control'] = 'must-revalidate, max-age=0'
28
+ resp['Content-Type'] = 'text/html; charset=utf-8'
29
29
  resp['ETag'] = "W/\"#{last_db_update.to_i}#{req.params.sort}\""
30
30
  resp['Last-Modified'] = last_db_update.httpdate
31
31
 
32
- resp.body = Murlsh::UrlBody.new(@config, @db, req)
32
+ resp.body = Murlsh::UrlBody.new(@config, @db, req, resp['Content-Type'])
33
33
 
34
34
  resp
35
35
  end
@@ -55,7 +55,7 @@ module Murlsh
55
55
  raise ActiveRecord::RecordInvalid.new(mu) unless mu.valid?
56
56
  Murlsh::Plugin.hooks('add_pre') { |p| p.run(mu, @config) }
57
57
  mu.save!
58
- Murlsh::Plugin.hooks('add_post') { |p| p.run(@config) }
58
+ Murlsh::Plugin.hooks('add_post') { |p| p.run(mu, @config) }
59
59
  response_body, response_code = [mu], 200
60
60
  rescue ActiveRecord::RecordInvalid => error
61
61
  response_body = {