-- 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 <> 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--