mirror of
https://github.com/vishapoberon/vipak.git
synced 2026-04-05 20:42:26 +00:00
lots of improvement in http module. continuing the work.
This commit is contained in:
parent
90a1d51b24
commit
02ef02fcce
1 changed files with 274 additions and 70 deletions
344
src/vpkHttp.Mod
344
src/vpkHttp.Mod
|
|
@ -1,19 +1,60 @@
|
||||||
MODULE vpkHttp;
|
MODULE vpkHttp;
|
||||||
IMPORT Strings, Internet, vpkLogger, Out;
|
IMPORT IntStr := oocIntStr, Strings, Internet, vpkLogger, Out, strTypes, strUtils;
|
||||||
|
CONST
|
||||||
|
defHeaderLength = 512;
|
||||||
|
defUserAgent = "oberon-http-client/1.0";
|
||||||
|
defHttpVersion = "HTTP/1.1";
|
||||||
|
defGetStr = "GET";
|
||||||
|
defHostStr = "HOST";
|
||||||
|
defUAStr = "User-Agent";
|
||||||
|
defAcceptStr = "Accept";
|
||||||
|
defEverythingStr = "*/*";
|
||||||
TYPE
|
TYPE
|
||||||
PString = POINTER TO ARRAY OF CHAR;
|
|
||||||
|
|
||||||
VAR
|
httpClient = POINTER TO httpClientDesc;
|
||||||
buff, buff2: PString;
|
|
||||||
|
|
||||||
PROCEDURE Empty*(VAR string: PString);
|
httpClientDesc = RECORD
|
||||||
|
host-, port-, path- : strTypes.pstring;
|
||||||
|
socket : Internet.Socket;
|
||||||
|
connectionFlag : BOOLEAN;
|
||||||
|
userAgent- : strTypes.pstring;
|
||||||
|
version- : strTypes.pstring;
|
||||||
|
eol : ARRAY 2 OF CHAR;
|
||||||
|
null : ARRAY 1 OF CHAR;
|
||||||
|
reqHeader- : POINTER TO ARRAY 5 OF strTypes.pstring;
|
||||||
|
rspnPstrings- : strTypes.pstrings;
|
||||||
|
rspnFirstLine- : strTypes.pstring;
|
||||||
|
rspnDate- : strTypes.pstring;
|
||||||
|
rspnServer- : strTypes.pstring;
|
||||||
|
rspnLastModified- : strTypes.pstring;
|
||||||
|
rspnETag- : strTypes.pstring;
|
||||||
|
rspnAcceptRanges- : strTypes.pstring;
|
||||||
|
rspnContentLength- : INTEGER;
|
||||||
|
rspnVary- : strTypes.pstring;
|
||||||
|
rspnContentType- : strTypes.pstring;
|
||||||
|
|
||||||
|
Create* : PROCEDURE(host, port, path: ARRAY OF CHAR): httpClient;
|
||||||
|
Get* : PROCEDURE(VAR http: httpClient): strTypes.pstring;
|
||||||
|
setUserAgent* : PROCEDURE(VAR http: httpClient; ua: ARRAY OF CHAR);
|
||||||
|
END;
|
||||||
|
|
||||||
|
VAR (* these variables are only for testing *)
|
||||||
|
http: httpClient;
|
||||||
|
answer, answer2: strTypes.pstring;
|
||||||
|
|
||||||
|
PROCEDURE Empty(VAR string: strTypes.pstring);
|
||||||
|
VAR i : LONGINT;
|
||||||
BEGIN
|
BEGIN
|
||||||
NEW(string, 1);
|
(*NEW(string, 512);
|
||||||
string[0] := 0X;
|
string[0] := 0X;*)
|
||||||
|
i := 0;
|
||||||
|
REPEAT
|
||||||
|
string[i] := 0X;
|
||||||
|
INC(i)
|
||||||
|
UNTIL i = LEN(string^) -1;
|
||||||
END Empty;
|
END Empty;
|
||||||
|
|
||||||
PROCEDURE getClean*(buff: ARRAY OF CHAR; VAR clean: PString);
|
PROCEDURE getClean(buff: ARRAY OF CHAR; VAR clean: strTypes.pstring);
|
||||||
VAR
|
VAR
|
||||||
i: INTEGER;
|
i: INTEGER;
|
||||||
lineIsHeader, EOL, notFirstLine: BOOLEAN;
|
lineIsHeader, EOL, notFirstLine: BOOLEAN;
|
||||||
|
|
@ -41,7 +82,7 @@ BEGIN
|
||||||
Strings.Extract(buff, i, Strings.Length(buff), clean^);
|
Strings.Extract(buff, i, Strings.Length(buff), clean^);
|
||||||
END getClean;
|
END getClean;
|
||||||
|
|
||||||
PROCEDURE AppendEOLAndClean(buff: ARRAY OF CHAR; VAR buffClean: PString);
|
PROCEDURE AppendEOLAndClean(buff: ARRAY OF CHAR; VAR buffClean: strTypes.pstring);
|
||||||
VAR
|
VAR
|
||||||
i: LONGINT;
|
i: LONGINT;
|
||||||
BEGIN
|
BEGIN
|
||||||
|
|
@ -54,85 +95,248 @@ BEGIN
|
||||||
buffClean[i + 2] := 0X;
|
buffClean[i + 2] := 0X;
|
||||||
END AppendEOLAndClean;
|
END AppendEOLAndClean;
|
||||||
|
|
||||||
PROCEDURE addHeader(key, val: ARRAY OF CHAR; VAR buff: PString);
|
PROCEDURE getHeader(VAR buff: ARRAY OF CHAR; key: ARRAY OF CHAR): strTypes.pstring;
|
||||||
VAR
|
|
||||||
header: PString;
|
|
||||||
headerLength: LONGINT;
|
|
||||||
BEGIN
|
|
||||||
headerLength := Strings.Length(key) + Strings.Length(val) + 2; (* 2 for ": " *)
|
|
||||||
NEW(header, headerLength + 1); (* +1 for null terminator *)
|
|
||||||
|
|
||||||
COPY(key, header^);
|
|
||||||
Strings.Append(": ", header^);
|
|
||||||
Strings.Append(val, header^);
|
|
||||||
|
|
||||||
AppendEOLAndClean(header^, buff);
|
|
||||||
END addHeader;
|
|
||||||
|
|
||||||
PROCEDURE getHeader(buff, key: ARRAY OF CHAR; VAR val: PString);
|
|
||||||
VAR
|
VAR
|
||||||
positionStart, valPositionStart, i: LONGINT;
|
positionStart, valPositionStart, i: LONGINT;
|
||||||
|
val: strTypes.pstring;
|
||||||
BEGIN
|
BEGIN
|
||||||
positionStart := Strings.Pos(key, buff, 0);
|
positionStart := Strings.Pos(key, buff, 0);
|
||||||
|
|
||||||
|
IF positionStart = -1 THEN
|
||||||
|
RETURN NIL;
|
||||||
|
END;
|
||||||
|
|
||||||
valPositionStart := positionStart + Strings.Length(key) + 1;
|
valPositionStart := positionStart + Strings.Length(key) + 1;
|
||||||
NEW(val, Strings.Length(buff) - valPositionStart + 1);
|
NEW(val, 8);
|
||||||
|
(*Empty(val);*)
|
||||||
i := 0;
|
i := 0;
|
||||||
REPEAT
|
REPEAT
|
||||||
val[i] := buff[valPositionStart + i];
|
val[i] := buff[valPositionStart + i];
|
||||||
|
IF (val[i] = 0AX) OR (val[i] = 0DX) THEN
|
||||||
|
val[i] := 0X
|
||||||
|
ELSE
|
||||||
|
val[i+1] := 0X
|
||||||
|
END;
|
||||||
INC(i);
|
INC(i);
|
||||||
UNTIL (ORD(val[i]) = 10) OR (i > Strings.Length(buff));
|
(*
|
||||||
|
Out.String("length is '"); Out.String(val^); Out.String("'"); Out.Ln;
|
||||||
|
Out.String("current character is '"); Out.Int(ORD(val[i-1]), 0); Out.String("'"); Out.Ln;
|
||||||
|
*)
|
||||||
|
UNTIL (val[i-1] = 0X) OR (i = Strings.Length(buff)-1);
|
||||||
|
RETURN val;
|
||||||
END getHeader;
|
END getHeader;
|
||||||
|
|
||||||
PROCEDURE get*(host, port, path: ARRAY OF CHAR; VAR buff: PString);
|
PROCEDURE readHeader(VAR http: httpClient):strTypes.pstring;
|
||||||
VAR
|
VAR
|
||||||
socket: Internet.Socket;
|
valueContentLength: LONGINT;
|
||||||
connectionFlag: BOOLEAN;
|
valueContentLengthString: strTypes.pstring;
|
||||||
valueContentLength: REAL;
|
header, buff: strTypes.pstring;
|
||||||
send, valueContentLengthString: PString;
|
headerBool : BOOLEAN;
|
||||||
sendClean: PString;
|
res: SHORTINT;
|
||||||
httpTail: ARRAY 16 OF CHAR;
|
i: INTEGER;
|
||||||
tmpBuff: PString;
|
|
||||||
sendLength: LONGINT;
|
|
||||||
BEGIN
|
BEGIN
|
||||||
Empty(buff);
|
NEW(header, defHeaderLength);
|
||||||
httpTail := " HTTP/1.1";
|
Empty(header);
|
||||||
|
NEW(buff, 2);
|
||||||
sendLength := Strings.Length(path) + Strings.Length(httpTail) + 4; (* 4 for "GET " *)
|
i := 0; headerBool := FALSE;
|
||||||
NEW(send, sendLength);
|
|
||||||
|
|
||||||
COPY("GET ", send^);
|
|
||||||
Strings.Append(path, send^);
|
|
||||||
Strings.Append(httpTail, send^);
|
|
||||||
|
|
||||||
AppendEOLAndClean(send^, sendClean);
|
|
||||||
connectionFlag := Internet.Write(socket, sendClean^);
|
|
||||||
|
|
||||||
addHeader("HOST", host, sendClean);
|
|
||||||
connectionFlag := Internet.Write(socket, sendClean^);
|
|
||||||
|
|
||||||
addHeader("User-Agent", "oberon-http-client/1.0", sendClean);
|
|
||||||
connectionFlag := Internet.Write(socket, sendClean^);
|
|
||||||
|
|
||||||
addHeader("Accept", "*/*", sendClean);
|
|
||||||
connectionFlag := Internet.Write(socket, sendClean^);
|
|
||||||
|
|
||||||
AppendEOLAndClean("", sendClean);
|
|
||||||
connectionFlag := Internet.Write(socket, sendClean^);
|
|
||||||
|
|
||||||
REPEAT
|
REPEAT
|
||||||
Empty(tmpBuff);
|
http^.connectionFlag := Internet.Read(http^.socket, buff^);
|
||||||
connectionFlag := Internet.Read(socket, tmpBuff^);
|
header[i] := buff[0];
|
||||||
|
Out.String("got character: "); Out.Int(ORD(buff[0]), 0); Out.Ln;
|
||||||
|
IF (header[i] = 0DX) THEN
|
||||||
|
http^.connectionFlag := Internet.Read(http^.socket, buff^);
|
||||||
|
INC(i); header[i] := buff[0];
|
||||||
|
Out.String("got character: "); Out.Int(ORD(buff[0]), 0); Out.Ln;
|
||||||
|
IF (header[i] = 0AX) THEN
|
||||||
|
http^.connectionFlag := Internet.Read(http^.socket, buff^);
|
||||||
|
INC(i); header[i] := buff^[0];
|
||||||
|
IF header[i] = 0DX THEN
|
||||||
|
http^.connectionFlag := Internet.Read(http^.socket, buff^);
|
||||||
|
INC(i); header[i] := buff^[0];
|
||||||
|
IF header[i] = 0AX THEN headerBool := TRUE END;
|
||||||
|
END;
|
||||||
|
END;
|
||||||
|
END;
|
||||||
|
INC(i);
|
||||||
|
header[i] := 0X;
|
||||||
|
Out.String("header is '"); Out.String(header^); Out.Char("'"); Out.Ln;
|
||||||
|
UNTIL headerBool;
|
||||||
|
RETURN header
|
||||||
|
END readHeader;
|
||||||
|
|
||||||
|
PROCEDURE processHeader(VAR http: httpClient; VAR hdr: ARRAY OF CHAR);
|
||||||
|
VAR
|
||||||
|
len, i, j: LONGINT;
|
||||||
|
ok: ARRAY 32 OF CHAR;
|
||||||
|
key, val: ARRAY 64 OF CHAR;
|
||||||
|
|
||||||
|
BEGIN
|
||||||
|
len := Strings.Length(hdr);
|
||||||
|
Out.String("header length is "); Out.Int(len, 0); Out.Ln;
|
||||||
|
|
||||||
|
(* getting string like 'HTTP/1.1 200 OK', hopefully *)
|
||||||
|
(* i := 0; j := 0;
|
||||||
|
REPEAT
|
||||||
|
ok[j] := hdr[i];
|
||||||
|
INC(i); INC(j);
|
||||||
|
UNTIL ok[i] = 0DX;
|
||||||
|
ok[i] := 0X;
|
||||||
|
*)
|
||||||
|
http^.rspnPstrings := strUtils.string2pstrings(hdr);
|
||||||
|
COPY(http^.rspnPstrings^[0]^, ok);
|
||||||
|
strUtils.string2pstring(ok, http^.rspnFirstLine);
|
||||||
|
Out.String("first line: '"); Out.String(http^.rspnFirstLine^);
|
||||||
|
Out.Char("'"); Out.Ln;
|
||||||
|
|
||||||
|
END processHeader;
|
||||||
|
|
||||||
|
PROCEDURE get*(VAR http: httpClient): strTypes.pstring;
|
||||||
|
VAR
|
||||||
|
tmpBuff, buff: strTypes.pstring;
|
||||||
|
BEGIN
|
||||||
|
(* Establish connection *)
|
||||||
|
Out.String("connecting to:"); Out.Ln;
|
||||||
|
Out.String("host: '"); Out.String(http^.host^); Out.Char("'"); Out.Ln;
|
||||||
|
Out.String("port: '"); Out.String(http^.port^); Out.Char("'"); Out.Ln;
|
||||||
|
Out.String("path: '"); Out.String(http^.path^); Out.Char("'"); Out.Ln;
|
||||||
|
http^.connectionFlag := Internet.Connect(http^.host^, http^.port^, http^.socket);
|
||||||
|
IF ~http^.connectionFlag THEN
|
||||||
|
Out.String("Connection failed");
|
||||||
|
Out.Ln;
|
||||||
|
HALT(5)
|
||||||
|
END;
|
||||||
|
|
||||||
|
Out.String("sending '"); Out.String(http^.reqHeader[0]^); Out.Char("'"); Out.Ln;
|
||||||
|
http^.connectionFlag := Internet.Write(http^.socket, http^.reqHeader[0]^);
|
||||||
|
Out.String("sending '"); Out.String(http^.reqHeader[1]^); Out.Char("'"); Out.Ln;
|
||||||
|
http^.connectionFlag := Internet.Write(http^.socket, http^.reqHeader[1]^);
|
||||||
|
Out.String("sending '"); Out.String(http^.reqHeader[2]^); Out.Char("'"); Out.Ln;
|
||||||
|
http^.connectionFlag := Internet.Write(http^.socket, http^.reqHeader[2]^);
|
||||||
|
Out.String("sending '"); Out.String(http^.reqHeader[3]^); Out.Char("'"); Out.Ln;
|
||||||
|
http^.connectionFlag := Internet.Write(http^.socket, http^.reqHeader[3]^);
|
||||||
|
Out.String("sending '"); Out.String(http^.reqHeader[4]^); Out.Char("'"); Out.Ln;
|
||||||
|
http^.connectionFlag := Internet.Write(http^.socket, http^.reqHeader[4]^);
|
||||||
|
|
||||||
|
tmpBuff := readHeader(http);
|
||||||
|
processHeader(http, tmpBuff^);
|
||||||
|
HALT(5);
|
||||||
|
(*
|
||||||
|
Out.String("over, getting header"); Out.Ln;
|
||||||
|
valueContentLengthString := getHeader(tmpBuff^, "Content-Length");
|
||||||
|
Out.String("got :'"); Out.String(valueContentLengthString^); Out.String("'"); Out.Ln;
|
||||||
|
IntStr.StrToInt(valueContentLengthString^, valueContentLength, res);
|
||||||
|
IF res # IntStr.strAllRight THEN
|
||||||
|
Out.String("not number"); Out.Ln; HALT(1)
|
||||||
|
ELSE
|
||||||
|
Out.String("got content length: "); Out.Int(valueContentLength, 0); Out.Ln
|
||||||
|
END;
|
||||||
|
i := 1;
|
||||||
|
REPEAT
|
||||||
|
NEW(buff, (valueContentLength+1)*i);
|
||||||
Strings.Append(tmpBuff^, buff^);
|
Strings.Append(tmpBuff^, buff^);
|
||||||
getHeader(buff^, "Content-Length", valueContentLengthString);
|
NEW(tmpBuff, valueContentLength+1);
|
||||||
Strings.StrToReal(valueContentLengthString^, valueContentLength);
|
http^.connectionFlag := Internet.Read(socket, tmpBuff^);
|
||||||
UNTIL ~connectionFlag OR (Strings.Length(buff^) > valueContentLength);
|
(*
|
||||||
|
Out.String("starting strings.append"); Out.Ln;
|
||||||
|
Strings.Append(tmpBuff^, buff^);
|
||||||
|
Out.String("ending strings.append"); Out.Ln;
|
||||||
|
Out.String("buff is '"); Out.String(buff^); Out.Char("'"); Out.Ln;
|
||||||
|
Out.String("tmpbuff2 is '"); Out.String(tmpBuff^); Out.Char("'"); Out.Ln;
|
||||||
|
*)
|
||||||
|
UNTIL ~http^.connectionFlag OR (Strings.Length(buff^) > valueContentLength);
|
||||||
Internet.Disconnect(socket);
|
Internet.Disconnect(socket);
|
||||||
|
RETURN buff
|
||||||
|
*)
|
||||||
END get;
|
END get;
|
||||||
|
|
||||||
|
PROCEDURE nextHeaderLine(key, val: ARRAY OF CHAR): strTypes.pstring;
|
||||||
|
VAR
|
||||||
|
header: strTypes.pstring;
|
||||||
|
headerLength, tmp: LONGINT;
|
||||||
|
BEGIN
|
||||||
|
headerLength := Strings.Length(key)
|
||||||
|
+ Strings.Length(val) + 2 (* 2 for ": " *)
|
||||||
|
+ 3; (* for eol: 0DX, 0AX, 0X *)
|
||||||
|
NEW(header, headerLength);
|
||||||
|
Out.String("header is now '"); Out.String(header^); Out.Char("'"); Out.Ln;
|
||||||
|
COPY(key, header^);
|
||||||
|
Out.String("header is now '"); Out.String(header^); Out.Char("'"); Out.Ln;
|
||||||
|
Strings.Append(": ", header^);
|
||||||
|
Out.String("header is now '"); Out.String(header^); Out.Char("'"); Out.Ln;
|
||||||
|
Strings.Append(val, header^);
|
||||||
|
|
||||||
|
Out.String("header is now '"); Out.String(header^); Out.Char("'"); Out.Ln;
|
||||||
|
|
||||||
|
tmp := Strings.Length(header^);
|
||||||
|
header^[tmp] := 0DX;
|
||||||
|
header^[tmp+1] := 0AX;
|
||||||
|
header^[tmp+2] := 0X;
|
||||||
|
Out.String("header is now '"); Out.String(header^); Out.Char("'"); Out.Ln;
|
||||||
|
RETURN header
|
||||||
|
END nextHeaderLine;
|
||||||
|
|
||||||
|
PROCEDURE formReqHeader(VAR http: httpClient);
|
||||||
|
VAR
|
||||||
|
pstr: strTypes.pstring;
|
||||||
|
len, tmp: INTEGER;
|
||||||
|
BEGIN
|
||||||
|
NEW(http^.reqHeader);
|
||||||
|
len := Strings.Length(http^.path^) + 1 (* space *) + Strings.Length(http^.version^) + 4 + 3 (* "GET " *);
|
||||||
|
NEW(http^.reqHeader[0], len);
|
||||||
|
COPY(defGetStr, http^.reqHeader[0]^);
|
||||||
|
Strings.Append(" ", http^.reqHeader[0]^);
|
||||||
|
Strings.Append(http^.path^, http^.reqHeader[0]^);
|
||||||
|
Strings.Append(" ", http^.reqHeader[0]^);
|
||||||
|
Strings.Append(http^.version^, http^.reqHeader[0]^);
|
||||||
|
tmp := Strings.Length(http^.reqHeader[0]^);
|
||||||
|
http^.reqHeader[0]^[tmp] := 0DX;
|
||||||
|
http^.reqHeader[0]^[tmp+1] := 0AX;
|
||||||
|
http^.reqHeader[0]^[tmp+2] := 0X;
|
||||||
|
(*
|
||||||
|
Strings.Append(http^.eol, http^.reqHeader[0]^);
|
||||||
|
Strings.Append(http^.null, http^.reqHeader[0]^);
|
||||||
|
*)
|
||||||
|
http^.reqHeader[1] := nextHeaderLine(defHostStr, http^.host^);
|
||||||
|
|
||||||
|
http^.reqHeader[2] := nextHeaderLine(defUAStr, http^.userAgent^);
|
||||||
|
|
||||||
|
http^.reqHeader[3] := nextHeaderLine(defAcceptStr, defEverythingStr);
|
||||||
|
|
||||||
|
NEW(http^.reqHeader[4], 3);
|
||||||
|
COPY(http^.eol, http^.reqHeader[4]^);
|
||||||
|
Strings.Append(http^.null, http^.reqHeader[4]^);
|
||||||
|
|
||||||
|
|
||||||
|
END formReqHeader;
|
||||||
|
|
||||||
|
|
||||||
|
PROCEDURE setuseragent*(VAR http: httpClient; ua: ARRAY OF CHAR);
|
||||||
|
BEGIN
|
||||||
|
strUtils.string2pstring(ua, http^.userAgent)
|
||||||
|
END setuseragent;
|
||||||
|
|
||||||
|
PROCEDURE Create*(host, port, path: ARRAY OF CHAR): httpClient;
|
||||||
|
VAR
|
||||||
|
http: httpClient;
|
||||||
|
BEGIN
|
||||||
|
NEW(http);
|
||||||
|
http^.eol[0] := 0DX; http^.eol[1] := 0AX; http^.null[0] := 0X;
|
||||||
|
strUtils.string2pstring(host, http^.host);
|
||||||
|
strUtils.string2pstring(port, http^.port);
|
||||||
|
strUtils.string2pstring(path, http^.path);
|
||||||
|
strUtils.string2pstring(defUserAgent, http^.userAgent);
|
||||||
|
strUtils.string2pstring(defHttpVersion, http^.version);
|
||||||
|
|
||||||
|
http^.Get := get;
|
||||||
|
http^.setUserAgent := setuseragent;
|
||||||
|
formReqHeader(http);
|
||||||
|
RETURN http
|
||||||
|
END Create;
|
||||||
|
|
||||||
BEGIN
|
BEGIN
|
||||||
(* Example usage of the get procedure *)
|
(* Example usage of the get procedure *)
|
||||||
(* get("example.com", "80", "/path", buff);
|
http := Create("norayr.am", "80", "/index.html");
|
||||||
getClean(buff^, buff2);
|
answer := http.Get(http);
|
||||||
vpkLogger.Log(buff2^); *)
|
getClean(answer^, answer2);
|
||||||
|
vpkLogger.Log(answer2^);
|
||||||
END vpkHttp.
|
END vpkHttp.
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue