diff options
| author | Charles.Forsyth <devnull@localhost> | 2006-12-22 17:07:39 +0000 |
|---|---|---|
| committer | Charles.Forsyth <devnull@localhost> | 2006-12-22 17:07:39 +0000 |
| commit | 37da2899f40661e3e9631e497da8dc59b971cbd0 (patch) | |
| tree | cbc6d4680e347d906f5fa7fca73214418741df72 /appl/svc/webget/wgutils.b | |
| parent | 54bc8ff236ac10b3eaa928fd6bcfc0cdb2ba46ae (diff) | |
20060303a
Diffstat (limited to 'appl/svc/webget/wgutils.b')
| -rw-r--r-- | appl/svc/webget/wgutils.b | 298 |
1 files changed, 298 insertions, 0 deletions
diff --git a/appl/svc/webget/wgutils.b b/appl/svc/webget/wgutils.b new file mode 100644 index 00000000..fdf5c375 --- /dev/null +++ b/appl/svc/webget/wgutils.b @@ -0,0 +1,298 @@ +implement WebgetUtils; + +include "sys.m"; + sys: Sys; + +include "draw.m"; + +include "string.m"; + +include "bufio.m"; + +include "imagefile.m"; + readgif, readjpg, readxbitmap: RImagefile; + +include "image2enc.m"; + image2enc: Image2enc; + +include "message.m"; + +include "url.m"; + +include "wgutils.m"; + Iobuf: import B; + +include "strinttab.m"; + T: StringIntTab; + +Msg, Nameval: import M; +ParsedUrl: import U; + +logfd: ref Sys->FD; + +# return from acceptmatch; and conv arg to readbody +BadConv, NoConv, Gif2xcompressed, Jpeg2xcompressed, Xbm2xcompressed: con iota; + +# Both extensions and Content-Types can be in same table. +# This array should be kept sorted +mtypes := array[] of { T->StringInt + ("ai", ApplPostscript), + ("application/html", TextHtml), + ("application/pdf", ApplPdf), + ("application/postscript", ApplPostscript), + ("application/rtf", ApplRtf), + ("application/x-html", TextHtml), + ("au", AudioBasic), + ("audio/au", AudioBasic), + ("audio/basic", AudioBasic), + ("bit", ImageXCompressed), + ("bit2", ImageXCompressed2), + ("eps", ApplPostscript), + ("gif", ImageGif), + ("htm", TextHtml), + ("html", TextHtml), + ("image/gif", ImageGif), + ("image/ief", ImageIef), + ("image/jpeg", ImageJpeg), + ("image/tiff", ImageTiff), + ("image/x-compressed", ImageXCompressed), + ("image/x-compressed2", ImageXCompressed2), + ("image/x-xbitmap", ImageXXBitmap), + ("jpe", ImageJpeg), + ("jpeg", ImageJpeg), + ("jpg", ImageJpeg), + ("pdf", ApplPdf), + ("ps", ApplPostscript), + ("text", TextPlain), + ("text/html", TextHtml), + ("text/plain", TextPlain), + ("text/x-html", TextHtml), + ("tif", ImageTiff), + ("tiff", ImageTiff), + ("txt", TextPlain), + ("video/mpeg", VideoMpeg), + ("video/quicktime", VideoQuicktime), +}; + +# following array must track media type def in wgutils.m +mnames := array[] of { + "application/x-unknown", + "text/plain", + "text/html", + "application/postscript", + "application/rtf", + "application/pdf", + "image/jpeg", + "image/gif", + "image/ief", + "image/tiff", + "image/x-compressed", + "image/x-compressed2", + "image/x-xbitmap", + "audio/basic", + "video/mpeg", + "video/quicktime" +}; + +init(m: Message, s: String, b: Bufio, u: Url, lfd: ref Sys->FD) +{ + sys = load Sys Sys->PATH; + + M = m; + S = s; + B = b; + U = u; + logfd = lfd; + T = load StringIntTab StringIntTab->PATH; + readgif = load RImagefile RImagefile->READGIFPATH; + readjpg = load RImagefile RImagefile->READJPGPATH; + readxbitmap = load RImagefile RImagefile->READXBMPATH; + image2enc = load Image2enc Image2enc->PATH; + if(T == nil || readgif == nil || readjpg == nil || readxbitmap == nil || image2enc == nil) { + sys->fprint(sys->fildes(2), "webget: failed to load T, readgif, readjpg, readxbitmap, or imageremap: %r\n"); + return; + } + readgif->init(B); + readjpg->init(B); + readxbitmap->init(B); +} + +# Return msg with error provoked by bad user action +usererr(r: ref Req, msg: string) : ref Msg +{ + m := Msg.newmsg(); + m.prefixline = sys->sprint("ERROR %s %s", r.reqid, msg); + m.bodylen = 0; + return m; +} + +okprefix(r: ref Req, mrep: ref Msg) +{ + (nil, sctype) := mrep.fieldval("content-type"); + if(sctype == "") + sctype = "text/html"; + else + sctype = canon_mtype(sctype); + (nil, cloc) := mrep.fieldval("content-location"); + if(cloc == "") + cloc = "unknown"; + mrep.prefixline = "OK " + string mrep.bodylen + " " + r.reqid + " " + sctype + " " + cloc; +} + +canon_mtype(s: string) : string +{ + # lowercase, and remove possible parameter + ls := S->tolower(s); + (ts, nil) := S->splitl(ls, "; "); + return ts; +} + +mediatype(s: string, dflt: int) : int +{ + (fnd, val) := T->lookup(mtypes, canon_mtype(s)); + if(!fnd) + val = dflt; + return val; +} + +acceptmatch(ctype: int, accept: string) : int +{ + conv := BadConv; + (nil,l) := sys->tokenize(accept, ","); + while(l != nil) { + a := S->drop(hd l, " \t"); + mt := mediatype(a, -1); + match := (ctype == mt) || (a == "*/*") + || ((ctype == ImageXCompressed || ctype == ImageXCompressed2) + && (mt == ImageJpeg || mt == ImageGif || mt == ImageXXBitmap)); + if(match) { + if(ctype == ImageGif) + conv = Gif2xcompressed; + else if(ctype == ImageJpeg) + conv = Jpeg2xcompressed; + else if(ctype == ImageXXBitmap) + conv = Xbm2xcompressed; + else + conv = NoConv; + break; + } + l = tl l; + } + return conv; +} + +# Get the body of the message whose header is in mrep, +# if io != nil. +# First check that the content type is acceptable. +# Image types will get converted into Inferno compressed format. +# If there is an error, return error string, else "". +# If no error, mrep will contain content-encoding, content-location, +# and content-type fields (guessed if they weren't orignally there). + +getdata(io: ref Iobuf, m: ref Msg, accept: string, url: ref ParsedUrl) : string +{ + (efnd, etype) := m.fieldval("content-encoding"); + if(efnd) + return "content is encoded: " + etype; + ctype := UnknownType; + (tfnd, sctype) := m.fieldval("content-type"); + if(tfnd) + ctype = mediatype(sctype, UnknownType); + else { + # try to guess type from extension + sctype = "(unknown)"; + (nil, name) := S->splitr(url.path, "/"); + if(name != "") { + (f, ext) := S->splitr(name, "."); + if(f != "" && ext != "") { + ctype = mediatype(ext, UnknownType); + if(ctype != UnknownType) { + sctype = mnames[ctype]; + m.update("content-type", sctype); + } + } + } + } + transform := acceptmatch(ctype, accept); + if(transform == BadConv) + return "Unacceptable media type: " + sctype; + (clfnd, cloc) := m.fieldval("content-location"); + if(!clfnd) { + cloc = url.tostring(); + m.update("content-location", cloc); + } + if(transform != NoConv) { + rawimg: ref RImagefile->Rawimage; + err: string; + if(transform == Gif2xcompressed) + (rawimg, err) = readgif->read(io); + else if(transform == Jpeg2xcompressed) + (rawimg, err) = readjpg->read(io); + else if(transform == Xbm2xcompressed) + (rawimg, err) = readxbitmap->read(io); + # if gif file has multiple images, we are supposed to animate, + # but the first one should be there + if(err != "" && err != "ReadGIF: can't handle multiple images in file") + return "error converting image file: " + err; + (data, mask, e) := image2enc->image2enc(rawimg, 1); + if(e != "") + return "error remapping and encoding image file: " + e; + if(mask == nil) + sctype = "image/x-compressed"; + else { + sctype = "image/x-compressed2"; + newdata := array[len data + len mask] of byte; + newdata[0:] = data[0:]; + newdata[len data:] = mask[0:]; + data = newdata; + } + m.body = data; + m.bodylen = len data; + m.update("content-type", sctype); + m.update("content-length", string m.bodylen); + } + else { + # io will be nil if m came from cache + if(io != nil) { + e := m.readbody(io); + if(e != "") + return "reading body: " + e; + } + } + return ""; +} + +# Change an accept spec from webget client into one we can send +# to http server. This means image/x-compressed must be +# changed into image formats we can handle: i.e., gif or jpeg +fixaccept(a: string) : string +{ + (nil,l) := sys->tokenize(a, ","); + ans := ""; + sep := ""; + while(l != nil) { + s := S->drop(hd l, " \t"); + if(s == "image/x-compressed") + ans += sep + "image/gif,image/jpeg,image/x-xbitmap"; + else + ans += sep + s; + sep = ","; + l = tl l; + } + if(ans == "") + ans = "*/*"; + return ans; +} + +log(c: ref Fid, msg: string) +{ + if(logfd != nil) { + # don't use print in case msg is longer than buf + s := ""; + if(c != nil) + s += (string c.fid) + ": "; + s += msg + "\n"; + b := array of byte s; + sys->write(logfd, b, len b); + } +} |
