-- File: HttpUtil.mesa - last edit: -- AOF 12-Jan-97 18:47:05 -- DLion 2-Mar-96 18:37:23 -- Copyright (C) 1995, 1996, 1997 by Freier's Garage. All rights reserved. DIRECTORY Ascii USING [CR, LF, NUL, SP, TAB], Environment USING [Block], Format USING [Number, NumberFormat, StringProc], Http USING [Handle, Object, ParseError, ParseErrorType], String USING [AppendChar, AppendString, CopyToNewString, StringBoundsFault], System USING [gmtEpoch, GreenwichMeanTime], TcpStream USING [CompletionCode, Handle], Time USING [Unpack, Unpacked, useGMT], WebOps USING [param], WebTool USING [data, Msg, Write, zone]; HttpUtil: MONITOR IMPORTS Format, Http, String, Time, WebOps, WebTool EXPORTS Http = BEGIN Create: PUBLIC <<Http>> PROC[tsH: TcpStream.Handle] RETURNS[http: Http.Handle] = BEGIN http ¬ WebTool.zone.NEW[Http.Object ¬ [ tsH: tsH, destroy: Destroy, reset: Reset, getByte: GetByte, flush: Flush, token: Token, lws: LWS, skip: Skip, logging: NIL, oneByte: [blockPointer: NIL, startIndex: 1, stopIndexPlusOne: 2]]]; http.oneByte.blockPointer ¬ LOOPHOLE[@http.pending]; END; --Create-- Destroy: PROC[http: Http.Handle] = BEGIN WebTool.zone.FREE[@http.url]; WebTool.zone.FREE[@http.referer]; WebTool.zone.FREE[@http.location]; WebTool.zone.FREE[@http.current]; WebTool.zone.FREE[@http.filename]; WebTool.zone.FREE[@http.mimeVersion]; WebTool.zone.FREE[@http]; END; --Destroy-- Reset: PROC[http: Http.Handle] = BEGIN http.mfH ¬ NIL; http.status ¬ 200; http.persist ¬ http.noCache ¬ FALSE; http.lastModified ¬ System.gmtEpoch; http.modifiedSince ¬ System.gmtEpoch; IF (http.url # NIL) THEN http.url.length ¬ 0; IF (http.referer # NIL) THEN http.referer.length ¬ 0; IF (http.current # NIL) THEN http.current.length ¬ 0; IF (http.location # NIL) THEN http.location.length ¬ 0; IF (http.filename # NIL) THEN http.filename.length ¬ 0; IF (http.mimeVersion # NIL) THEN http.mimeVersion.length ¬ 0; END; --Reset-- GetByte: PROC[http: Http.Handle] = BEGIN cc: TcpStream.CompletionCode ¬ http.tsH.get[http.oneByte].completionCode; SELECT cc FROM normal, pushed => IF (WebTool.data.level = verbose) THEN BEGIN c: STRING ¬ [1]; c[0] ¬ LOOPHOLE[http.oneByte.blockPointer[1]]; IF (c[0] # Ascii.LF) THEN WebTool.Write[c]; END; ENDCASE => BEGIN WebTool.Write["Unexpected TCP completion: "G]; WebTool.Write[SELECT cc FROM timeout => "timeout\n"G, closing => "closing\n"G, ENDCASE => "endUrgent\n"G]; ERROR Http.ParseError[endOfStream]; END; END; --GetByte-- Token: PROC[http: Http.Handle, stop: CHAR] RETURNS[LONG STRING] = BEGIN SELECT TRUE FROM (http.current = NIL) => http.current ¬ WebTool.zone.NEW[ StringBody[WebOps.param.tokenLength]]; (http.current.length # 0) => RETURN[http.current]; ENDCASE; IF (http.pending = Ascii.NUL) THEN http.getByte[http]; [] ¬ http.lws[http]; --need to get by that WHILE (http.pending # stop) DO ENABLE String.StringBoundsFault => BEGIN ns: LONG STRING ¬ String.CopyToNewString[ http.current, WebTool.zone, WebOps.param.tokenDelta]; WebTool.zone.FREE[@http.current]; WebTool.Msg["\nLogging buffer extension!!!!\n"G]; http.current ¬ ns; RESUME; END; String.AppendChar[s: http.current, c: http.pending]; http.getByte[http]; ENDLOOP; RETURN[http.current]; END; --Token-- LWS: PROC[http: Http.Handle] RETURNS[BOOLEAN ¬ TRUE] = BEGIN DO SELECT TRUE FROM (http.skip[http, Ascii.SP]) => NULL; (http.skip[http, Ascii.TAB]) => NULL; ENDCASE => EXIT; ENDLOOP; END; --LWS-- Flush: PROC[http: Http.Handle] RETURNS[BOOLEAN ¬ TRUE] = BEGIN http.current.length ¬ 0; [] ¬ Token[http, Ascii.CR]; --get up to the CR [] ¬ Skip[http, Ascii.CR]; --consume the CR IF (~Skip[http, Ascii.LF]) THEN ERROR Http.ParseError[space]; END; --Flush-- Skip: PROC[http: Http.Handle, stop: CHAR] RETURNS[BOOLEAN] = BEGIN http.current.length ¬ 0; IF (http.pending = Ascii.NUL) THEN http.getByte[http]; IF (http.pending # stop) THEN RETURN[FALSE]; http.pending ¬ Ascii.NUL; RETURN[TRUE]; END; --Skip-- weekday: ARRAY [0..7) OF LONG STRING ¬ [ "Mon "G, "Tue "G, "Wed "G, "Thu "G, "Fri "G, "Sat "G, "Sun "G]; month: ARRAY [0..12) OF LONG STRING ¬ [ "Jan"G, "Feb"G, "Mar"G, "Apr"G, "May"G, "Jun"G, "Jul"G, "Aug"G, "Sep"G, "Oct"G, "Nov"G, "Dec"G]; HttpDate: PUBLIC --Http-- PROC[ proc: Format.StringProc, time: System.GreenwichMeanTime, clientData: LONG POINTER] = BEGIN date: LONG STRING ¬ [30]; nf: Format.NumberFormat ¬ [columns: 3]; lproc: Format.StringProc = {String.AppendString[date, s]}; unpacked: Time.Unpacked ¬ Time.Unpack[time, Time.useGMT]; String.AppendString[date, weekday[unpacked.weekday]]; String.AppendString[date, month[unpacked.month]]; Format.Number[lproc, unpacked.day, nf]; Format.Number[lproc, unpacked.hour, nf]; nf.columns ¬ 2; nf.zerofill ¬ TRUE; String.AppendChar[date, ':]; Format.Number[lproc, unpacked.minute, nf]; String.AppendChar[date, ':]; Format.Number[lproc, unpacked.second, nf]; nf.zerofill ¬ FALSE; nf.columns ¬ 5; Format.Number[lproc, unpacked.year, nf]; String.AppendString[date, " GMT"G]; proc[date]; END; --HttpDate-- YafDate: PUBLIC --Http-- PROC[ proc: Format.StringProc, time: System.GreenwichMeanTime, clientData: LONG POINTER ¬ NIL] = BEGIN date: LONG STRING ¬ [30]; nf: Format.NumberFormat ¬ []; lproc: Format.StringProc = {String.AppendString[date, s]}; unpacked: Time.Unpacked ¬ Time.Unpack[time, Time.useGMT]; nf.zerofill ¬ FALSE; nf.columns ¬ 2; Format.Number[lproc, unpacked.day, nf]; String.AppendChar[date, '/]; String.AppendString[date, month[unpacked.month]]; String.AppendChar[date, '/]; nf.zerofill ¬ FALSE; nf.columns ¬ 4; Format.Number[lproc, unpacked.year, nf]; String.AppendChar[date, ':]; nf.zerofill ¬ TRUE; nf.columns ¬ 2; Format.Number[lproc, unpacked.hour, nf]; String.AppendChar[date, ':]; Format.Number[lproc, unpacked.minute, nf]; String.AppendChar[date, ':]; Format.Number[lproc, unpacked.second, nf]; String.AppendString[date, " 0000"]; proc[date]; END; --HttpDate-- END... --HttpUtil.mesa--