class Sgfa::Web::Binder
Binder
web interface
Constants
- BinderTable
- DocketEach
each entry
- EditAttach
- EditAttachButton
- EditForm
- EditTag
- EditTagButton
- EditTagOpt
- EditTagSel
- EntryDisp
- HistoryDisp
- HistoryItem
- HistoryTable
- InfoTable
- JacketPost
- JacketsForm
- JacketsRow
- JacketsTable
- ListPrefix
- ListTable
- ListTag
- LogRow
- LogTable
- PageDiv
Page division
- PageSize
- PageSizeMax
- TagRow
- TagTable
- UsersForm
- UsersRow
- UsersTable
- ValuesForm
- ValuesRow
- ValuesTable
Public Instance Methods
Process the request
This is a seperate method to simplify the flow control by using return.
# File lib/sgfa/web/binder.rb, line 74 def _call(env) # defaults env['sgfa.status'] = :badreq env['sgfa.title'] = 'SFGA Error' env['sfga.navbar'] = '' env['sgfa.html'] = 'Invalid request' path = env['PATH_INFO'].split('/') if path.empty? jacket = nil else path.shift if path[0].empty? jacket = path.shift end # just the binder if !jacket case env['REQUEST_METHOD'] when 'GET'; return _get_jackets(env, path) when 'POST'; return _post_binder(env) else; return end end # special binder pages if jacket[0] == '_' return if env['REQUEST_METHOD'] != 'GET' case jacket when '_jackets' return _get_jackets(env, path) when '_users' return _get_users(env, path) when '_values' return _get_values(env, path) when '_info' return _get_binder(env, path) else return end end # jacket info stored env['sgfa.jacket.url'] = jacket env['sgfa.jacket.name'] = _escape_un(jacket) cmd = path.shift # just the jacket if !cmd case env['REQUEST_METHOD'] when 'GET'; return _get_tag(env, path) when 'POST'; return _post_jacket(env) else; return end end # jacket stuff return if env['REQUEST_METHOD'] != 'GET' case cmd when '_edit'; return _get_edit(env, path) when '_entry'; return _get_entry(env, path) when '_history'; return _get_history(env, path) when '_attach'; return _get_attach(env, path) when '_tag'; return _get_tag(env, path) when '_log'; return _get_log(env, path) when '_list'; return _get_list(env, path) when '_info'; return _get_info(env, path) when '_docket'; return _get_docket(env, path) else; return end end
Display an entry
# File lib/sgfa/web/binder.rb, line 722 def _disp_entry(env, ent, opts={}) enum = ent.entry rnum = ent.revision hnum = ent.history tl = ent.tags tags = "Tags:<br>\n" if tl.empty? tags << "none\n" else tl.sort.each do |tag| tags << _link_tag(env, tag, _escape_html(tag)) + "<br>\n" end end al = ent.attachments att = "Attachments:<br>\n" if al.empty? att << "none\n" else al.each do |anum, hnum, name| att << _link_attach(env, enum, anum, hnum, name, _escape_html(name)) + "<br>\n" end end if rnum == 1 prev = 'previous' else prev = _link_revision(env, enum, rnum-1, 'previous') end curr = opts[:current] ? '' : _link_entry(env, enum, 'current') edit = _link_edit(env, enum, 'edit') hist = _link_history(env, hnum, hnum.to_s) hash = ent.hash hash << ('<br>Jacket: %s' % ent.jacket) if opts[:jacket] body = EntryDisp % [ _escape_html(ent.title), _escape_html(ent.body), ent.time.localtime.strftime('%F %T %z'), rnum, prev, curr, hist, edit, tags, att, hash ] return body end
Display jacket list
# File lib/sgfa/web/binder.rb, line 351 def _disp_jackets(env, jackets, tr) rows = '' jackets.each do |jnam, jinfo| perms = jinfo[:perms] ps = perms.empty? ? '-' : _escape_html(perms.join(', ')) rows << JacketsRow % [_link_jacket(env, jnam, _escape_html(jnam)), _escape_html(jinfo[:title]), ps] end html = JacketsTable % rows html << JacketsForm % env['SCRIPT_NAME'] if tr[:perms].include?('manage') return html end
Display users
# File lib/sgfa/web/binder.rb, line 436 def _disp_users(env, users, tr) rows = '' users.each do |unam, pl| perms = pl.empty? ? '-' : pl.join(', ') rows << UsersRow % [ _escape_html(unam), _escape_html(perms) ] end html = UsersTable % rows html << (UsersForm % env['SCRIPT_NAME']) if tr[:perms].include?('manage') return html end
Display values
# File lib/sgfa/web/binder.rb, line 491 def _disp_values(env, values, tr) rows = '' values.each do |vnam, vset| rows << ValuesRow % [ _escape_html(vnam), _escape_html(vset) ] end html = ValuesTable % rows html << (ValuesForm % env['SCRIPT_NAME']) if tr[:perms].include?('manage') return html end
Get an attachment
# File lib/sgfa/web/binder.rb, line 946 def _get_attach(env, path) _navbar_jacket(env, 'Attachment') spec = path.shift return if !spec ma = /^(\d+)-(\d+)-(\d+)$/.match(spec) return if !ma name = path.shift return if !name return if !path.empty? enum, anum, hnum = ma[1,3].map{|st| st.to_i} name = _escape_un(name) ext = name.rpartition('.')[2] if ext.empty? mime = 'application/octet-stream' else mime = Rack::Mime.mime_type('.' + ext) end tr = _trans(env) file = env['sgfa.binder'].read_attach(tr, enum, anum, hnum) env['sgfa.status'] = :ok env['sgfa.headers'] = { 'Content-Length' => file.size.to_s, 'Content-Type' => mime, 'Content-Disposition' => 'attachment', } env['sgfa.file'] = FileBody.new(file) end
Get binder info
# File lib/sgfa/web/binder.rb, line 379 def _get_binder(env, path) _navbar_binder(env, 'Binder') return if !path.empty? tr = _trans(env) info = env['sgfa.binder'].binder_info(tr) env['sgfa.status'] = :ok env['sgfa.html'] = BinderTable % [ info[:id_hash], _escape_html(info[:id_text]), info[:jackets].size, info[:users].size, info[:values].size, _escape_html(tr[:perms].join(', ')) ] end
Get a docket view
# File lib/sgfa/web/binder.rb, line 587 def _get_docket(env, path) _navbar_jacket(env, 'Docket') # tag, page, perpage tag = path.empty? ? Jacket::TagAll : _escape_un(path.shift) page = path.empty? ? 1 : path.shift.to_i page = 1 if page == 0 rck = Rack::Request.new(env) params = rck.GET per = params['perpage'] ? params['perpage'].to_i : 0 per = PageSize if( per == 0 || per > PageSizeMax ) # get tr = _trans(env) size, ents = env['sgfa.binder'].read_tag(tr, tag, (page-1)*per, per, raw: true) html = "<div class='tagname'>Docket: %s</div>\n" % _escape_html(tag) if ents.size == 0 html << 'No entries' else rows = '' ents.reverse_each do |item| if item.is_a?(Entry) rows << _disp_entry(env, item, jacket: false, current: true) else enum, rnum, hnum, time, title, tcnt, acnt = item if rnum == 1 prev = 'previous' else prev = _link_revision(env, enum, rnum-1, 'previous') end hist = _link_history(env, hnum, hnum.to_s) rows << DocketEach % [ _escape_html(title), time.localtime.strftime("%F %T %z"), rnum, prev, hist, tcnt, acnt, ] end end html << rows end link = '%s/%s/_docket/%s' % [ env['SCRIPT_NAME'], env['sgfa.jacket.url'], _escape(tag) ] query = (per != PageSize) ? { 'perpage' => per.to_s } : nil pages = PageDiv % _link_pages(page, per, size, link, query) env['sgfa.status'] = :ok env['sgfa.html'] = html + pages end
Get edit form
# File lib/sgfa/web/binder.rb, line 1127 def _get_edit(env, path) _navbar_jacket(env, 'Edit') tr = _trans(env) # get entry if path.empty? enum = 0 rnum = 0 ent = Entry.new ent.title = 'Title' ent.body = 'Body' ent.time = Time.now else enum = path.shift.to_i return if enum == 0 || !path.empty? ent = env['sgfa.binder'].read_entry(tr, enum) rnum = ent.revision end # get tag list and prefixes lst = env['sgfa.binder'].read_list(tr) prefix = {} lst.each do |tag| idx = tag.index(':') next unless idx pre = tag[0,idx].strip post = tag[idx+1..-1].strip if prefix[pre] prefix[pre].push post else prefix[pre] = [post] end end # attachments atts = '' acnt = 0 ent.attachments.each do |anum, hnum, name| atts << EditAttach % [acnt, _escape_html(name), acnt, anum, acnt, ''] acnt += 1 end atts << EditAttach % [acnt, '', acnt, 0, acnt, EditAttachButton] # tags tags = '' cnt = 0 prefix.keys.sort.each do |pre| lst = prefix[pre] px = _escape_html(pre) opts = '' lst.sort.each do |post| ex = _escape_html(post) opts << EditTagOpt % [px, ex, ex] end tags << EditTagSel % [px, cnt, px, opts] cnt += 1 end tcnt = 0 ent.tags.sort.each do |tag| tags << EditTag % [tcnt, _escape_html(tag), ''] tcnt += 1 end tags << EditTag % [tcnt, '', EditTagButton] # the page html = EditForm % [ env['SCRIPT_NAME'], env['sgfa.jacket.url'], _escape_html(ent.title), ent.time.localtime.strftime('%F %T %z'), _escape_html(ent.body), atts, tags, enum, rnum, acnt+1, tcnt+1, acnt, tcnt ] env['sgfa.status'] = :ok env['sgfa.html'] = html end
Get an entry
# File lib/sgfa/web/binder.rb, line 693 def _get_entry(env, path) _navbar_jacket(env, 'Entry') return if path.empty? enum = path.shift.to_i rnum = path.empty? ? 0 : path.shift.to_i return if enum == 0 tr = _trans(env) ent = env['sgfa.binder'].read_entry(tr, enum, rnum) env['sgfa.status'] = :ok env['sgfa.html'] = _disp_entry(env, ent) end
Display a history item
# File lib/sgfa/web/binder.rb, line 791 def _get_history(env, path) _navbar_jacket(env, 'History') return if path.empty? hnum = path.shift.to_i return if hnum == 0 tr = _trans(env) hst = env['sgfa.binder'].read_history(tr, hnum) hnum = hst.history plnk = (hnum == 1) ? 'Previous' : _link_history(env, hnum-1, 'Previous') nlnk = _link_history(env, hnum+1, 'Next') rows = "" hst.entries.each do |enum, rnum, hash| disp = "Entry %d-%d" % [enum, rnum] rows << (HistoryItem % [_link_revision(env, enum, rnum, disp), hash]) end hst.attachments.each do |enum, anum, hash| disp = "Attach %d-%d-%d" % [enum, anum, hnum] rows << HistoryItem % [_link_attach(env, enum, anum, hnum, hash + '.bin', disp), hash] end tab = HistoryTable % rows body = HistoryDisp % [ hnum, tab, hst.time.localtime.strftime('%F %T %z'), _escape_html(hst.user), plnk, nlnk, hst.hash, hst.jacket ] env['sgfa.status'] = :ok env['sgfa.html'] = body end
Get jacket info
# File lib/sgfa/web/binder.rb, line 918 def _get_info(env, path) _navbar_jacket(env, 'Jacket') return if !path.empty? tr = _trans(env) info = env['sgfa.binder'].binder_info(tr) hst = env['sgfa.binder'].read_history(tr, 0) if hst hmax = hst.history emax = hst.entry_max time = hst.time.localtime.strftime('%F %T %z') else hmax = 0 emax = 0 time = 'none' end jinf = info[:jackets][env['sgfa.jacket.name']] env['sgfa.status'] = :ok env['sgfa.html'] = InfoTable % [ jinf[:id_text], jinf[:id_hash], time, hmax, emax ] end
Get jacket list
# File lib/sgfa/web/binder.rb, line 332 def _get_jackets(env, path) _navbar_binder(env, 'Jackets') if !path.empty? env['sgfa.status'] = :badreq env['sgfa.html'] = 'Invalid URL requested' return end tr = _trans(env) info = env['sgfa.binder'].binder_info(tr) env['sgfa.status'] = :ok env['sgfa.html'] = _disp_jackets(env, info[:jackets], tr) end
Get list of tags
# File lib/sgfa/web/binder.rb, line 839 def _get_list(env, path) _navbar_jacket(env, 'List') bnd = env['sgfa.binder'] tr = _trans(env) lst = bnd.read_list(tr) # sort into prefixed & regular prefix = {} regular = [] lst.each do |tag| idx = tag.index(':') if !idx regular.push tag next end pre = tag[0,idx].strip if prefix[pre] prefix[pre].push tag else prefix[pre] = [tag] end end # regular & prefix list rows = '' if path.empty? prefix.keys.sort.each do |pre| size = prefix[pre].size rows << ListPrefix % [_link_prefix(env, pre, _escape_html(pre)), size] end regular.sort.each do |tag| size, ents = bnd.read_tag(tr, tag, 0, 0) rows << ListTag % [ _link_tag(env, tag, _escape_html(tag)), size, _link_tag(env, tag, 'Tag'), _link_dock(env, tag, 'Docket') ] end # list entire prefix else pre = _escape_un(path.shift) return if !path.empty? if !prefix[pre] env['sgfa.status'] = :notfound env['sgfa.html'] = 'Tag prefix not found' return end prefix[pre].sort.each do |tag| size, ents = bnd.read_tag(tr, tag, 0, 0) rows << ListTag % [ _link_tag(env, tag, _escape_html(tag)), size, _link_tag(env, tag, 'Tag'), _link_dock(env, tag, 'Docket') ] end end env['sgfa.status'] = :ok env['sgfa.html'] = ListTable % rows end
Get the log
# File lib/sgfa/web/binder.rb, line 653 def _get_log(env, path) _navbar_jacket(env, 'Log') page = path.empty? ? 1 : path.shift.to_i page = 1 if page == 0 return if !path.empty? rck = Rack::Request.new(env) params = rck.GET per = params['perpage'] ? params['perpage'].to_i : 0 if per == 0 || per > PageSizeMax per = PageSize end tr = _trans(env) size, hsts = env['sgfa.binder'].read_log(tr, (page-1)*per, per) if hsts.size == 0 env['sgfa.html'] = 'No history' env['sgfa.status'] = :notfound else rows = '' hsts.each do |hnum, time, user, ecnt, acnt| rows << LogRow % [ hnum, _link_history(env, hnum, time.localtime.strftime('%F %T %z')), _escape_html(user), ecnt, acnt ] end link = '%s/%s/_log' % [env['SCRIPT_NAME'], env['sgfa.jacket.url']] query = (per != PageSize) ? { 'perpage' => per.to_s } : nil env['sgfa.status'] = :ok env['sgfa.html'] = (LogTable % rows) + _link_pages(page, per, size, link, query) end end
Get a tag
# File lib/sgfa/web/binder.rb, line 521 def _get_tag(env, path) _navbar_jacket(env, 'Tag') if path.empty? tag = '_all' else tag = _escape_un(path.shift) end page = path.empty? ? 1 : path.shift.to_i page = 1 if page == 0 rck = Rack::Request.new(env) params = rck.GET per = params['perpage'] ? params['perpage'].to_i : 0 if per == 0 || per > PageSizeMax per = PageSize end tr = _trans(env) size, ents = env['sgfa.binder'].read_tag(tr, tag, (page-1)*per, per) if ents.size == 0 html = 'No entries' else rows = '' ents.reverse_each do |enum, rnum, hnum, time, title, tcnt, acnt| rows << TagRow % [ time.localtime.strftime("%F %T %z"), _link_entry(env, enum, _escape_html(title)), acnt, tcnt, _link_edit(env, enum, 'edit') ] end html = TagTable % [_escape_html(tag), rows] end link = '%s/%s/_tag/%s' % [ env['SCRIPT_NAME'], env['sgfa.jacket.url'], _escape(tag) ] query = (per != PageSize) ? { 'perpage' => per.to_s } : nil pages = PageDiv % _link_pages(page, per, size, link, query) env['sgfa.status'] = :ok env['sgfa.html'] = html + pages end
Get users
# File lib/sgfa/web/binder.rb, line 417 def _get_users(env, path) _navbar_binder(env, 'Users') if !path.empty? env['sgfa.status'] = :badreq env['sgfa.html'] = 'Invalid URL requested' return end tr = _trans(env) info = env['sgfa.binder'].binder_info(tr) env['sgfa.status'] = :ok env['sgfa.html'] = _disp_users(env, info[:users], tr) end
Get values
# File lib/sgfa/web/binder.rb, line 472 def _get_values(env, path) _navbar_binder(env, 'Values') if !path.empty? env['sgfa.status'] = :badreq env['sgfa.html'] = 'Invalid URL requested' return end tr = _trans(env) info = env['sgfa.binder'].binder_info(tr) env['sgfa.status'] = :ok env['sgfa.html'] = _disp_values(env, info[:values], tr) end
Link to an attachments
# File lib/sgfa/web/binder.rb, line 292 def _link_attach(env, enum, anum, hnum, name, disp) "<a href='%s/%s/_attach/%d-%d-%d/%s'>%s</a>" % [ env['SCRIPT_NAME'], env['sgfa.jacket.url'], enum, anum, hnum, _escape_path(name), disp ] end
Link to a docket
# File lib/sgfa/web/binder.rb, line 268 def _link_dock(env, tag, disp) "<a href='%s/%s/_docket/%s'>%s</a>" % [ env['SCRIPT_NAME'], env['sgfa.jacket.url'], _escape(tag), disp ] end
Link to edit entry
# File lib/sgfa/web/binder.rb, line 208 def _link_edit(env, enum, disp) "<a href='%s/%s/_edit/%d'>%s</a>" % [ env['SCRIPT_NAME'], env['sgfa.jacket.url'], enum, disp ] end
Link to display an entry
# File lib/sgfa/web/binder.rb, line 220 def _link_entry(env, enum, disp) "<a href='%s/%s/_entry/%d'>%s</a>" % [ env['SCRIPT_NAME'], env['sgfa.jacket.url'], enum, disp ] end
Link to a history item
# File lib/sgfa/web/binder.rb, line 245 def _link_history(env, hnum, disp) "<a href='%s/%s/_history/%d'>%s</a>" % [ env['SCRIPT_NAME'], env['sgfa.jacket.url'], hnum, disp ] end
Link to a jacket
# File lib/sgfa/web/binder.rb, line 201 def _link_jacket(env, jnam, disp) "<a href='%s/%s'>%s</a>" % [env['SCRIPT_NAME'], _escape(jnam), disp] end
Link to a tag prefix
# File lib/sgfa/web/binder.rb, line 280 def _link_prefix(env, pre, disp) "<a href='%s/%s/_list/%s'>%s</a>" % [ env['SCRIPT_NAME'], env['sgfa.jacket.url'], _escape(pre), disp ] end
Link to a specific revision
# File lib/sgfa/web/binder.rb, line 232 def _link_revision(env, enum, rnum, disp) "<a href='%s/%s/_entry/%d/%d'>%s</a>" % [ env['SCRIPT_NAME'], env['sgfa.jacket.url'], enum, rnum, disp ] end
Link to a tag
# File lib/sgfa/web/binder.rb, line 256 def _link_tag(env, tag, disp) "<a href='%s/%s/_tag/%s'>%s</a>" % [ env['SCRIPT_NAME'], env['sgfa.jacket.url'], _escape(tag), disp ] end
Handle binder post
# File lib/sgfa/web/binder.rb, line 1320 def _post_binder(env) _navbar_binder(env, 'Edit') rck = Rack::Request.new(env) params = rck.POST # stupid kludge to fix bad standards inplementation. # apparently browsers don't set the charset correctly so rack defaults # to ASCII-8BIT, and then everything dies when there's actually UTF-8 # present. Since modern browsers actually send UTF-8 when we ask for # it, just force it to UTF-8 and hope for the best. params.each{ |key, val| val.force_encoding('utf-8') if val.is_a?(String) } tr = _trans(env) tr[:title] = 'Test title' tr[:body] = 'Test description of action' bnd = env['sgfa.binder'] # jacket if params['create'] _navbar_binder(env, 'Jackets') ['jacket', 'newname', 'title', 'perms'].each do |fn| next if params[fn] raise Error::Limits, 'Bad form submission' end perms = params['perms'].split(',').map{|it| it.strip } title = params['title'] newname = params['newname'] jacket = params['jacket'] tr[:jacket] = jacket info = bnd.binder_info(tr) oj = info[:jackets][jacket] if oj newname ||= jacket title = oj['title'] if title.empty? jck = bnd.jacket_edit(tr, newname, title, perms) env['sgfa.message'] = 'Jacket edited.' else jck = bnd.jacket_create(tr, title, perms) env['sgfa.message'] = 'Jacket created.' end env['sgfa.status'] = :ok env['sgfa.html'] = _disp_jackets(env, jck, tr) # user elsif params['set'] _navbar_binder(env, 'Users') ['user', 'perms'].each do |fn| next if params[fn] raise Error::Limits, 'Bad form submission' end perms = params['perms'].split(',').map{|it| it.strip } users = bnd.binder_user(tr, params['user'], perms) env['sgfa.status'] = :ok env['sgfa.message'] = 'User edited.' env['sgfa.html'] = _disp_users(env, users, tr) # binder elsif params['assign'] _navbar_binder(env, 'Values') ['value', 'state'].each do |fn| next if params[fn] raise Error::Limits, 'Bad form submission' end vals = { params['value'] => params['state'] } values = bnd.binder_values(tr, vals) env['sgfa.status'] = :ok env['sgfa.message'] = 'Values assigned.' env['sgfa.html'] = _disp_values(env, values, tr) end end
Handle jacket post
# File lib/sgfa/web/binder.rb, line 1215 def _post_jacket(env) _navbar_jacket(env, 'Edit') rck = Rack::Request.new(env) params = rck.POST # stupid kludge to fix bad standards inplementation. # apparently browsers don't set the charset correctly so rack defaults # to ASCII-8BIT, and then everything dies when there's actually UTF-8 # present. Since modern browsers actually send UTF-8 when we ask for # it, just force it to UTF-8 and hope for the best. params.each{ |key, val| val.force_encoding('utf-8') if val.is_a?(String) } # validate fields present JacketPost.each do |fn| next if params[fn] raise Error::Limits, 'Bad form submission' end tagcnt = params['tagcnt'].to_i attcnt = params['attcnt'].to_i tagcnt.times do |ix| next if params['tag%d' % ix] raise Error::Limits, 'Bad form submission' end attcnt.times do |ix| next if params['attnumb%d' % ix] raise Error::Limits, 'Bad form submission' end # get the entry being edited enum = params['entry'].to_i rnum = params['revision'].to_i tr = _trans(env) if enum != 0 ent = env['sgfa.binder'].read_entry(tr, enum, rnum) else ent = Entry.new end # tags oldt = ent.tags newt = [] tagcnt.times do |ix| tx = 'tag%d' % ix if !params[tx].empty? newt.push params[tx] end end # attachments attcnt.times do |ix| anum = params['attnumb%d' % ix].to_i name = params['attname%d' % ix] file = params['attfile%d' % ix] # copy uploaded file if file && file != '' ftmp = env['sgfa.binder'].temp IO::copy_stream(file[:tempfile], ftmp) file[:tempfile].close! else ftmp = nil end # new file if anum == 0 next if !ftmp name = file[:filename] if name == '' ent.attach(name, ftmp) # old file else ent.replace(anum, ftmp) if ftmp if name != '' ent.rename(anum, name) elsif ftmp ent.rename(anum, file[:filename]) else ent.delete(anum) end end end # general ent.title = params['title'] ent.body = params['body'] begin time = Time.parse(params['time']) ent.time = time rescue ArgumentError end oldt.each{|tag| ent.untag(tag) if !newt.include?(tag) } newt.each{|tag| ent.tag(tag) if !oldt.include?(tag) } env['sgfa.binder'].write(tr, [ent]) env['sgfa.status'] = :ok env['sgfa.message'] = 'Entry edited.' env['sgfa.html'] = _disp_entry(env, ent) end
Request
@param env [Hash] The Rack environment for this request, with app
specific options
@option env [String] ‘sgfa.binder.url’ URL encoded binder name @option env [String] ‘sgfa.binder.name’ The name of the binder @option env [Binder] ‘sgfa.binder’ The binder @option env [String] ‘sgfa.user’ The user name @option env [Array] ‘sgfa.groups’ Array of groups the user belongs to
# File lib/sgfa/web/binder.rb, line 38 def call(env) _call(env) return response(env) rescue Error::Permission => exp env['sgfa.status'] = :deny env['sgfa.html'] = _escape_html(exp.message) return response(env) rescue Error::Conflict => exp env['sgfa.status'] = :conflict env['sgfa.html'] = _escape_html(exp.message) return response(env) rescue Error::NonExistent => exp env['sgfa.status'] = :notfound env['sgfa.html'] = _escape_html(exp.message) return response(env) rescue Error::Limits => exp env['sgfa.status'] = :badreq env['sgfa.html'] = _escape_html(exp.message) return response(env) rescue Error::Corrupt => exp env['sgfa.status'] = :servererror env['sgfa.html'] = _escape_html(exp.message) return response(env) end