parsav  Diff

Differences From Artifact [68c9cc33d4]:

To Artifact [dafa2dc374]:


     1      1   -- vim: ft=terra
     2      2   local util = lib.util
     3      3   local secmode = lib.enum { 'public', 'private', 'lockdown', 'isolate' }
     4      4   local pstring = lib.mem.ptr(int8)
     5         -local mimetypes = {
     6         -	{'html', 'text/html'};
     7         -	{'json', 'application/json'};
     8         -	{'json', 'application/activity+json'};
     9         -	{'json', 'application/ld+json'};
    10         -	{'mkdown', 'text/markdown'};
    11         -	{'text', 'text/plain'};
    12         -	{'ansi', 'text/x-ansi'};
    13         -}
    14      5   
    15      6   local struct srv
    16      7   local struct cfgcache {
    17      8   	secret: pstring
    18      9   	pol_sec: secmode.t
    19     10   	pol_reg: bool
    20     11   	pol_autoherald: bool
................................................................................
   149    140   
   150    141   terra lib.store.post:publish(s: &srv)
   151    142   	self:comp()
   152    143   	self.posted = lib.osclock.time(nil)
   153    144   	self.discovered = self.posted
   154    145   	self.chgcount = 0
   155    146   	self.edited = 0
          147  +	self.uri = nil -- only for foreign posts
          148  +	self.convoheaduri = nil -- ditto
   156    149   	self.id = s:post_create(self)
   157    150   	return self.id
   158    151   end
   159    152   
   160         -local struct convo {
   161         -	srv: &srv
   162         -	con: &lib.net.mg_connection
   163         -	msg: &lib.net.mg_http_message
   164         -	aid: uint64 -- 0 if logged out
   165         -	aid_issue: lib.store.timepoint
   166         -	who: &lib.store.actor -- who we're logged in as, if aid ~= 0
   167         -	peer: lib.store.inet
   168         -	reqtype: lib.http.mime.t -- negotiated content type
   169         -	method: lib.http.method.t
   170         -	live_last: lib.store.timepoint
   171         -	uploads: lib.mem.vec(lib.http.upload)
   172         -	body: lib.str.t
   173         --- cache
   174         -	ui_hue: uint16
   175         -	navbar: lib.mem.ptr(int8)
   176         -	actorcache: lib.mem.cache(lib.mem.ptr(lib.store.actor),32) -- naive cache to avoid unnecessary queries
   177         --- private
   178         -	varbuf: lib.mem.ptr(int8)
   179         -	vbofs: &int8
   180         -}
   181         -
   182         -struct convo.page {
   183         -	title: pstring
   184         -	body: pstring
   185         -	class: pstring
   186         -	cache: bool
   187         -}
   188         -
   189         -local usrdefs = {
   190         -	str = {
   191         -		['acl-follow'    ] = {cfgfld = 'usrdef_pol_follow', fallback = 'local'};
   192         -		['acl-follow-req'] = {cfgfld = 'usrdef_pol_follow_req', fallback = 'all'};
   193         -	};
   194         -}
   195         -
   196         -terra convo:matchmime(mime: lib.http.mime.t): bool
   197         -	return self.reqtype == [lib.http.mime.none]
   198         -		or self.reqtype == mime
   199         -end
   200         -
   201         -terra convo:usercfg_str(uid: uint64, setting: pstring): pstring
   202         -	var set = self.srv:actor_conf_str_get(&self.srv.pool, uid, setting)
   203         -	if not set then
   204         -		[(function()
   205         -			local q = quote return pstring.null() end
   206         -			for key, dfl in pairs(usrdefs.str) do
   207         -				local rv
   208         -				if dfl.cfgfld then
   209         -					rv = quote
   210         -						var cf = self.srv.cfg.[dfl.cfgfld]
   211         -					in terralib.select(not cf, pstring([dfl.fallback]), cf) end
   212         -				elseif dfl.lit then rv = dfl.lit end
   213         -				q = quote
   214         -					if setting:cmp([key]) then return [rv] else [q] end
   215         -				end
   216         -			end
   217         -			return q
   218         -		end)()]
   219         -	else return set end
   220         -end
   221         -
          153  +local convo = terralib.loadfile 'convo.t'(srv)
   222    154   -- this is unfortunately necessary to work around a terra bug
   223    155   -- it can't seem to handle forward-declarations of structs in C
   224    156   
   225    157   local getpeer
   226    158   do local struct strucheader {
   227    159   		next: &lib.net.mg_connection
   228    160   		mgr: &lib.net.mg_mgr
................................................................................
   229    161   		peer: lib.net.mg_addr
   230    162   	}
   231    163   	terra getpeer(con: &lib.net.mg_connection)
   232    164   		return [&strucheader](con).peer
   233    165   	end
   234    166   end
   235    167   
   236         -terra convo:uid2actor_live(uid: uint64)
   237         -	var actor = self.srv:actor_fetch_uid(uid)
   238         -	if actor:ref() then
   239         -		if self.aid ~= 0 and self.who.id ~= uid then
   240         -			actor(0).relationship = self.srv:actor_rel_calc(self.who.id, uid)
   241         -		else -- defensive branch
   242         -			actor(0).relationship = lib.store.relationship {
   243         -				agent = 0, patient = uid;
   244         -				rel   = [lib.store.relation.null],
   245         -				recip = [lib.store.relation.null],
   246         -			}
   247         -		end
   248         -	end
   249         -	return actor
   250         -end
   251         -
   252         -terra convo:uid2actor(uid: uint64)
   253         -	var actor: &lib.store.actor = nil
   254         -	for j = 0, self.actorcache.top do
   255         -		if uid == self.actorcache(j).ptr.id then
   256         -			actor = self.actorcache(j).ptr
   257         -			break
   258         -		end
   259         -	end
   260         -	if actor == nil then
   261         -		actor = self.actorcache:insert(self:uid2actor_live(uid)).ptr
   262         -	end
   263         -	return actor
   264         -end
   265         -
   266         -terra convo:rawpage(code: uint16, pg: convo.page, hdrs: lib.mem.ptr(lib.http.header))
   267         -	var doc = data.view.docskel {
   268         -		instance = self.srv.cfg.instance;
   269         -		title = pg.title;
   270         -		body = pg.body;
   271         -		class = pg.class;
   272         -		navlinks = self.navbar;
   273         -		attr = '';
   274         -	}
   275         -	var attrbuf: int8[32]
   276         -	if self.aid ~= 0 and self.ui_hue ~= 323 then
   277         -		var hdecbuf: int8[21]
   278         -		var hdec = lib.math.decstr(self.ui_hue, &hdecbuf[20])
   279         -		lib.str.cpy(&attrbuf[0], ' style="--hue:')
   280         -		lib.str.cpy(&attrbuf[14], hdec)
   281         -		var len = &hdecbuf[20] - hdec 
   282         -		lib.str.cpy(&attrbuf[14] + len, '"')
   283         -		doc.attr = &attrbuf[0]
   284         -	end
   285         -
   286         -	if self.method == [lib.http.method.head]
   287         -		then doc:head(self.con,code,hdrs)
   288         -		else doc:send(self.con,code,hdrs)
   289         -	end
   290         -end
   291         -
   292         -terra convo:statpage(code: uint16, pg: convo.page)
   293         -	var hdrs = array(
   294         -		lib.http.header { key = 'Content-Type', value = 'text/html; charset=UTF-8' },
   295         -		lib.http.header { key = 'Cache-Control', value = 'no-store' }
   296         -	)
   297         -	self:rawpage(code,pg, [lib.mem.ptr(lib.http.header)] {
   298         -		ptr = &hdrs[0];
   299         -		ct = [hdrs.type.N] - lib.trn(pg.cache,1,0);
   300         -	})
   301         -end
   302         -
   303         -terra convo:livepage(pg: convo.page, lastup: lib.store.timepoint)
   304         -	var nbuf: int8[21]
   305         -	var hdrs = array(
   306         -		lib.http.header { key = 'Content-Type', value = 'text/html; charset=UTF-8' },
   307         -		lib.http.header { key = 'Cache-Control', value = 'no-store' },
   308         -		lib.http.header {
   309         -			key = 'X-Live-Newest-Artifact';
   310         -			value = lib.math.decstr(lastup, &nbuf[20]);
   311         -		},
   312         -		lib.http.header { key = 'Content-Length', value = '0' }
   313         -	)
   314         -	if self.live_last ~= 0 and self.live_last == lastup then
   315         -		lib.net.mg_printf(self.con, 'HTTP/1.1 %s', lib.http.codestr(200))
   316         -		for i = 0, [hdrs.type.N] do
   317         -			lib.net.mg_printf(self.con, '%s: %s\r\n', hdrs[i].key, hdrs[i].value)
   318         -		end
   319         -		lib.net.mg_printf(self.con, '\r\n')
   320         -	else
   321         -		self:rawpage(200, pg, [lib.mem.ptr(lib.http.header)] {
   322         -			ptr = &hdrs[0], ct = 3
   323         -		})
   324         -	end
   325         -end
   326         -
   327         -terra convo:stdpage(pg: convo.page) self:statpage(200, pg) end
   328         -
   329         -terra convo:bytestream_trusted(lockdown: bool, mime: pstring, data: lib.mem.ptr(uint8))
   330         -	var lockhdr = "Content-Security-Policy: sandbox; default-src 'none'; form-action 'none'; navigate-to 'none';\r\n"
   331         -	if not lockdown then lockhdr = "" end
   332         -	lib.net.mg_printf(self.con, "HTTP/1.1 200 OK\r\nContent-Type: %.*s\r\nContent-Length: %llu\r\n%sX-Content-Options: nosniff\r\n\r\n", mime.ct, mime.ptr, data.ct + 2, lockhdr)
   333         -	lib.net.mg_send(self.con, data.ptr, data.ct)
   334         -	lib.net.mg_send(self.con, '\r\n', 2)
   335         -end
   336         -
   337         -terra convo:json(data: pstring)
   338         -	self:bytestream_trusted(false, 'application/activity+json; charset=utf-8', data:blob())
   339         -end
   340         -
   341         -terra convo:bytestream(mime: pstring, data: lib.mem.ptr(uint8))
   342         -	-- TODO this is not a satisfactory solution; it's a bandaid on a gaping
   343         -	-- chest wound. ultimately we need to compile a whitelist of safe mime
   344         -	-- types as part of mimelib, but that is no small task. for now, this
   345         -	-- will keep the patient from immediately bleeding out
   346         -	if mime:cmp('text/html') or
   347         -		mime:cmp('text/xml') or
   348         -		mime:cmp('application/xhtml+xml') or
   349         -		mime:cmp('application/vnd.wap.xhtml+xml')
   350         -	then -- danger will robinson
   351         -		mime = 'text/plain'
   352         -	elseif mime:cmp('application/x-shockwave-flash') then
   353         -		mime = 'application/octet-stream'
   354         -	end
   355         -	self:bytestream_trusted(true, mime, data)
   356         -end
   357         -
   358         -terra convo:reroute_cookie(dest: rawstring, cookie: rawstring)
   359         -	var hdrs = array(
   360         -		lib.http.header { key = 'Content-Type', value = 'text/html; charset=UTF-8' },
   361         -		lib.http.header { key = 'Location',     value = dest },
   362         -		lib.http.header { key = 'Set-Cookie',   value = cookie }
   363         -	)
   364         -
   365         -	var body = data.view.docskel {
   366         -		instance = self.srv.cfg.instance.ptr;
   367         -		title = 'rerouting';
   368         -		body = 'you are being redirected';
   369         -		class = 'error';
   370         -		navlinks = '';
   371         -		attr = '';
   372         -	}
   373         -
   374         -	body:send(self.con, 303, [lib.mem.ptr(lib.http.header)] {
   375         -		ptr = &hdrs[0], ct = [hdrs.type.N] - lib.trn(cookie == nil,1,0)
   376         -	})
   377         -end
   378         -
   379         -terra convo:reroute(dest: rawstring) self:reroute_cookie(dest,nil) end
   380         -
   381         -terra convo:installkey(dest: rawstring, aid: uint64)
   382         -	var sesskey: int8[lib.session.maxlen + #lib.session.cookiename + #"=; Path=/" + 1]
   383         -	do var p = &sesskey[0]
   384         -		p = lib.str.ncpy(p, [lib.session.cookiename .. '='], [#lib.session.cookiename + 1])
   385         -		p = p + lib.session.cookie_gen(self.srv.cfg.secret, aid, lib.osclock.time(nil), p)
   386         -		lib.dbg('sending cookie ',{&sesskey[0],15})
   387         -		p = lib.str.ncpy(p, '; Path=/', 9)
   388         -	end
   389         -	self:reroute_cookie(dest, &sesskey[0])
   390         -end
   391         - 
   392         -terra convo:stra(sz: intptr) -- convenience function
   393         -	var s: lib.str.acc
   394         -	s:pool(&self.srv.pool,sz)
   395         -	return s
   396         -end
   397         -
   398         -convo.methods.qstr = macro(function(self, ...) -- convenience string builder
   399         -	local exp = {...}
   400         -	return `lib.str.acc{}:pcompose(&self.srv.pool, [exp]):finalize()
   401         -end)
   402         -
   403         -terra convo:complain(code: uint16, title: rawstring, msg: rawstring)
   404         -	if msg == nil then msg = "i'm sorry, dave. i can't let you do that" end
   405         -
   406         -	if self:matchmime(lib.http.mime.html) then
   407         -		var body = [convo.page] {
   408         -			title = self:qstr('error :: ', title);
   409         -			body = self:qstr('<div class="message"><img class="icon" src="/s/warn.svg"><h1>',title,'</h1><p>',msg,'</p></div>');
   410         -			class = 'error';
   411         -			cache = false;
   412         -		}
   413         -
   414         -		self:statpage(code, body)
   415         -	else
   416         -		var pg = lib.http.page { respcode = code, body = pstring.null() }
   417         -		var ctt = lib.http.mime.none
   418         -		if self:matchmime(lib.http.mime.json) then ctt = lib.http.mime.json
   419         -			pg.body = ([lib.tpl.mk'{"_parsav_error":@$ekind, "_parsav_error_desc":@$edesc}']
   420         -				{ekind = title, edesc = msg}):poolstr(&self.srv.pool)
   421         -		elseif self:matchmime(lib.http.mime.text) then ctt = lib.http.mime.text
   422         -			pg.body = self:qstr('error: ',title,'\n',msg)
   423         -		elseif self:matchmime(lib.http.mime.mkdown) then ctt = lib.http.mime.mkdown
   424         -			pg.body = self:qstr('# error :: ',title,'\n\n',msg)
   425         -		elseif self:matchmime(lib.http.mime.ansi) then ctt = lib.http.mime.ansi
   426         -			pg.body = self:qstr('\27[1;31merror :: ',title,'\27[m\n',msg)
   427         -		end
   428         -		var cthdr = lib.http.header { 'Content-Type', 'text/plain' }
   429         -		if ctt == lib.http.mime.none then
   430         -			pg.headers.ct = 0
   431         -		else
   432         -			pg.headers = lib.typeof(pg.headers) { &cthdr, 1 }
   433         -			switch ctt do
   434         -				case [ctt.type](lib.http.mime.json) then
   435         -					cthdr.value = 'application/json'
   436         -				end
   437         -				escape
   438         -					for i,v in ipairs(mimetypes) do local key,mime = v[1],v[2]
   439         -						if key ~= 'json' then
   440         -							emit quote case [ctt.type](lib.http.mime.[key]) then cthdr.value = [mime] end end
   441         -						end
   442         -					end
   443         -				end
   444         -			end
   445         -		end
   446         -		pg:send(self.con)
   447         -	end
   448         -end
   449         -
   450         -terra convo:fail(code: uint16)
   451         -	switch code do
   452         -		escape
   453         -			local stderrors = {
   454         -				{400, 'bad request', "the action you have attempted on this resource is not meaningful"};
   455         -				{401, 'unauthorized', "this resource is not available at your clearance level"};
   456         -				{403, 'forbidden', "we can neither confirm nor deny the existence of this resource"};
   457         -				{404, 'resource not found', "that resource is not extant on or known to this server"};
   458         -				{405, 'method not allowed', "the method you have attempted on this resource is not meaningful"};
   459         -				{406, 'not acceptable', "none of the suggested content types are a viable representation of this resource"};
   460         -				{500, 'internal server error', "parsav did a fucksy wucksy"};
   461         -			}
   462         -
   463         -			for i,v in ipairs(stderrors) do
   464         -				emit quote case uint16([v[1]]) then
   465         -					self:complain([v])
   466         -				end end
   467         -			end
   468         -		end
   469         -		else self:complain(500,'unknown error','an unrecognized error was thrown. this is a bug')
   470         -	end
   471         -end
   472         -
   473         -terra convo:confirm(title: pstring, msg: pstring, cancel: pstring)
   474         -	var conf = data.view.confirm {
   475         -		title = title;
   476         -		query = msg;
   477         -		cancel = cancel;
   478         -	}
   479         -	var ti: lib.str.acc ti:pcompose(&self.srv.pool,'confirm :: ', title)
   480         -	var body = conf:poolstr(&self.srv.pool) -- defer body:free()
   481         -	var cf = [convo.page] {
   482         -		title = ti:finalize();
   483         -		class = 'query';
   484         -		body = body; cache = false;
   485         -	}
   486         -	self:stdpage(cf)
   487         -	--cf.title:free()
   488         -end
   489         -
   490         -convo.methods.assertpow = macro(function(self, pow)
   491         -	return quote
   492         -		var ok = true
   493         -		if self.aid == 0 or self.who.rights.powers.[pow:asvalue()]() == false then
   494         -			ok = false
   495         -			self:complain(403,'insufficient privileges',['you lack the <strong>'..pow:asvalue()..'</strong> power and cannot perform this action'])
   496         -		end
   497         -	in ok end
   498         -end)
   499         -
   500         -local pstr2mg, mg2pstr
   501         -do -- aaaaaaaaaaaaaaaaaaaaaaaa
   502         -	mgstr = lib.util.find(lib.net.mg_http_message.entries, function(v)
   503         -		if v.field == 'body' or v[1] == 'body' then return v.type end
   504         -	end)
   505         -	terra pstr2mg(p: pstring): mgstr
   506         -		return mgstr { ptr = p.ptr, len = p.ct }
   507         -	end
   508         -	terra mg2pstr(m: mgstr): pstring
   509         -		return pstring { ptr = m.ptr, ct = m.len }
   510         -	end
   511         -end
   512         -
   513         --- CALL ONLY ONCE PER VAR
   514         -terra convo:postv_next(name: pstring, start: &pstring)
   515         -	if self.varbuf.ptr == nil then
   516         -		self.varbuf = self.srv.pool:alloc(int8, self.msg.body.len + self.msg.query.len)
   517         -		self.vbofs = self.varbuf.ptr
   518         -	end
   519         -	var conv = pstr2mg(@start)
   520         -	var o = lib.net.mg_http_get_var(
   521         -		&conv,
   522         -		name.ptr, self.vbofs,
   523         -		self.varbuf.ct - (self.vbofs - self.varbuf.ptr)
   524         -	)
   525         -	if o > 0 then
   526         -		start:advance(name.ct + o + 2)
   527         -		var r = self.vbofs
   528         -		self.vbofs = self.vbofs + o + 1
   529         -		@(self.vbofs - 1) = 0
   530         -		var norm = lib.str.normalize([lib.mem.ptr(int8)]{ptr = r, ct = o})
   531         -		return norm.ptr, norm.ct
   532         -	else return nil, 0 end
   533         -end
   534         -terra convo:postv(name: pstring)
   535         -	var start = mg2pstr(self.msg.body)
   536         -	return self:postv_next(name, &start)
   537         -end
   538         -terra convo:ppostv(name: pstring)
   539         -	var s,l = self:postv(name)
   540         -	return pstring { ptr = s, ct = l }
   541         -end
   542         -do
   543         -	local struct postiter { co: &convo where: pstring name: pstring }
   544         -	terra convo:eachpostv(name: pstring)
   545         -		return postiter { co = self, where = mg2pstr(self.msg.body), name = name } 
   546         -	end
   547         -	postiter.metamethods.__for = function(self, body)
   548         -		return quote
   549         -			while true do
   550         -				var str, len = self.co:postv_next(self.name, &self.where)
   551         -				if str == nil then break end
   552         -				[ body(`pstring {str, len}) ]
   553         -			end
   554         -		end
   555         -	end
   556         -end
   557         -
   558         -terra convo:getv(name: rawstring)
   559         -	if self.varbuf.ptr == nil then
   560         -		self.varbuf = self.srv.pool:alloc(int8, self.msg.query.len + self.msg.body.len)
   561         -		self.vbofs = self.varbuf.ptr
   562         -	end
   563         -	var o = lib.net.mg_http_get_var(&self.msg.query, name, self.vbofs, self.varbuf.ct - (self.vbofs - self.varbuf.ptr))
   564         -	if o > 0 then
   565         -		var r = self.vbofs
   566         -		self.vbofs = self.vbofs + o + 1
   567         -		@(self.vbofs - 1) = 0
   568         -		var norm = lib.str.normalize([lib.mem.ptr(int8)]{ptr = r, ct = o})
   569         -		return norm.ptr, norm.ct
   570         -	else return nil, 0 end
   571         -end
   572         -terra convo:pgetv(name: rawstring)
   573         -	var s,l = self:getv(name)
   574         -	return pstring { ptr = s, ct = l }
   575         -end
   576         -
   577    168   local route = {} -- these are defined in route.t, as they need access to renderers
   578    169   terra route.dispatch_http ::  {&convo, lib.mem.ptr(int8)} -> {}
   579    170   
   580         -local mimevar = symbol(lib.mem.ref(int8))
   581         -local mimeneg = `lib.http.mime.none
   582         -
   583         -for i, t in ipairs(mimetypes) do
   584         -	local name, mime = t[1], t[2]
   585         -	mimeneg = quote
   586         -		var ret: lib.http.mime.t
   587         -		if lib.str.ncmp(mimevar.ptr, mime, lib.math.biggest(mimevar.ct, [#mime])) == 0 then
   588         -			ret = [lib.http.mime[name]]
   589         -		else ret = [mimeneg] end
   590         -	in ret end
   591         -end
   592         -
   593    171   local handle = {
   594    172   	http = terra(con: &lib.net.mg_connection, event_kind: int, event: &opaque, userdata: &opaque)
   595    173   		var server = [&srv](userdata)
   596    174   		var mgpeer = getpeer(con)
   597    175   		-- var pbuf: int8[128]
   598    176   
   599    177   		-- the peer property is currently broken and there is precious
................................................................................
   634    212   				  co.body.ptr = msg.body.ptr co.body.ct = msg.body.len
   635    213   
   636    214   				-- first, check for an accept header. if it's there, we need to
   637    215   				-- iterate over the values and pick the highest-priority one
   638    216   				do var acc = lib.http.findheader(msg, 'Accept')
   639    217   					-- TODO handle q-value
   640    218   					if acc ~= nil and acc.ptr ~= nil then
   641         -						var [mimevar] = [lib.mem.ref(int8)] { ptr = acc.ptr }
          219  +						var mimevar = [pstring] { ptr = acc.ptr }
          220  +						lib.dbg('accept header is ', {acc.ptr,acc.ct})
   642    221   						var i = 0 while i < acc.ct do
   643    222   							if acc.ptr[i] == @',' or acc.ptr[i] == @';' then
   644    223   								mimevar.ct = (acc.ptr+i) - mimevar.ptr
   645         -								var t = [mimeneg]
   646         -								if t ~= lib.http.mime.none then
   647         -									co.reqtype = t
          224  +								var mk = lib.mime.lookup(mimevar)
          225  +								if mk ~= nil and mk.output ~= lib.http.mime.none then
          226  +									co.reqtype = mk.output
   648    227   									goto foundtype
   649    228   								end
   650    229   
   651    230   								if acc.ptr[i] == @';' then -- fast-forward over q
   652    231   									for j=i+1,acc.ct do i=j
   653    232   										if acc.ptr[j] == @',' then break end
   654    233   									end
................................................................................
   661    240   
   662    241   								mimevar.ptr = acc.ptr + i + 1
   663    242   							end
   664    243   							i=i+1
   665    244   						end
   666    245   						if co.reqtype == lib.http.mime.none then
   667    246   							mimevar.ct = acc.ct - (mimevar.ptr - acc.ptr)
   668         -							co.reqtype = [mimeneg]
   669         -							if co.reqtype == lib.http.mime.none then
   670         -								co.reqtype = lib.http.mime.html
          247  +							var mk = lib.mime.lookup(mimevar)
          248  +							if mk ~= nil and mk.output ~= lib.http.mime.none then
          249  +								co.reqtype = mk.output
   671    250   							end
   672    251   						end
   673         -					else co.reqtype = lib.http.mime.html end
          252  +					end
   674    253   				::foundtype::end
   675    254   
   676    255   				-- we need to check if there's any cookies sent with the request,
   677    256   				-- and if so, whether they contain any credentials. this will be
   678    257   				-- used to set the auth parameters in the http conversation
   679    258   				var cookies_p = lib.http.findheader(msg, 'Cookie')
   680    259   				if cookies_p ~= nil and cookies_p.ptr ~= nil then
................................................................................
   878    457   							end
   879    458   							bsr:free()
   880    459   							upmap:free()
   881    460   						end
   882    461   					end
   883    462   				end
   884    463   
          464  +				var mtt = lib.http.mime._str(co.reqtype)
          465  +				lib.dbg('routing with negotiated type of ', {mtt.ptr,mtt.ct})
   885    466   				route.dispatch_http(&co, uri)
   886    467   
   887    468   				::fail::
   888    469   				if co.uploads.run > 0 then
   889    470   					for i=0,co.uploads.sz do
   890    471   						co.uploads(i).filename:free()
   891    472   						co.uploads(i).field:free()