2023-03-07 13:27:41 +01:00
|
|
|
"#stream.spl" import
|
|
|
|
"#net.spl" import
|
2023-03-06 03:45:16 +01:00
|
|
|
|
2023-03-06 04:28:51 +01:00
|
|
|
"http" net:register
|
|
|
|
|
|
|
|
construct net:http namespace {
|
2023-03-06 03:45:16 +01:00
|
|
|
Request
|
|
|
|
Response
|
2023-03-06 14:56:49 +01:00
|
|
|
help
|
2023-03-06 03:45:16 +01:00
|
|
|
}
|
|
|
|
|
2023-03-06 04:28:51 +01:00
|
|
|
construct net:http:Request {
|
2023-03-06 03:45:16 +01:00
|
|
|
host port
|
|
|
|
method path
|
|
|
|
headers
|
|
|
|
body
|
|
|
|
;
|
|
|
|
construct { this | with host port method path this ;
|
|
|
|
host this:=host
|
|
|
|
port this:=port
|
|
|
|
method this:=method
|
|
|
|
path this:=path
|
|
|
|
List:new this:=headers
|
|
|
|
"" this:=body
|
|
|
|
this
|
|
|
|
}
|
|
|
|
add-header { this | with header this ;
|
|
|
|
header this:headers:push
|
|
|
|
this
|
|
|
|
}
|
|
|
|
set-body { this | with body this ;
|
|
|
|
body this:=body
|
|
|
|
this
|
|
|
|
}
|
2023-03-06 04:28:51 +01:00
|
|
|
send { net:http:Response | with this ;
|
2023-03-06 03:45:16 +01:00
|
|
|
def stream this:host this:port StreamTypes:tcp:create =stream
|
2023-03-06 04:28:51 +01:00
|
|
|
def response net:http:Response:new =response
|
2023-03-06 03:45:16 +01:00
|
|
|
|
|
|
|
this:method:to-bytes stream:write-exact;
|
2023-04-08 09:51:40 +02:00
|
|
|
" " :to-bytes stream:write-exact;
|
2023-03-06 03:45:16 +01:00
|
|
|
this:path:to-bytes stream:write-exact;
|
2023-04-08 09:51:40 +02:00
|
|
|
" HTTP/1.0\r\n" :to-bytes stream:write-exact;
|
2023-03-06 03:45:16 +01:00
|
|
|
|
2023-04-08 09:51:40 +02:00
|
|
|
"Host: " :to-bytes stream:write-exact;
|
2023-03-06 03:45:16 +01:00
|
|
|
this:host:to-bytes stream:write-exact;
|
|
|
|
"\r\nConnection: Close\r\nUser-Agent: http.spl v0.1 2023-03 (spl@mail.tudbut.de)\r\n"
|
2023-04-08 09:51:40 +02:00
|
|
|
:to-bytes stream:write-exact;
|
2023-03-06 03:45:16 +01:00
|
|
|
|
|
|
|
{ | with header ;
|
|
|
|
header:to-bytes stream:write-exact;
|
|
|
|
"\r\n" stream:write-exact;
|
|
|
|
} this:headers:foreach
|
|
|
|
|
2023-04-08 09:51:40 +02:00
|
|
|
"Content-Length: " :to-bytes stream:write-exact;
|
2023-03-06 03:45:16 +01:00
|
|
|
def body this:body:to-bytes =body
|
|
|
|
body:len _str:to-bytes stream:write-exact;
|
2023-04-08 09:51:40 +02:00
|
|
|
"\r\n\r\n" :to-bytes stream:write-exact;
|
2023-03-06 03:45:16 +01:00
|
|
|
|
|
|
|
body stream:write-exact;
|
|
|
|
stream:flush;
|
|
|
|
|
2023-03-06 14:56:49 +01:00
|
|
|
def response 1024 stream:read-to-end =response
|
|
|
|
|
|
|
|
response net:http:Response:new:read-from-bytes
|
2023-03-06 03:45:16 +01:00
|
|
|
|
|
|
|
stream:close;
|
2023-03-06 14:56:49 +01:00
|
|
|
}
|
|
|
|
}
|
2023-03-06 03:45:16 +01:00
|
|
|
|
2023-03-06 14:56:49 +01:00
|
|
|
construct net:http:help namespace {
|
|
|
|
;
|
|
|
|
assert-str { | with expected iter _ ;
|
|
|
|
[ { | pop iter:next } (expected _array):len:foreach ] _str
|
|
|
|
expected _str
|
|
|
|
eq not if {
|
|
|
|
"Expected " expected concat throw
|
|
|
|
}
|
|
|
|
}
|
|
|
|
until-str { str | with expected iter _ ;
|
|
|
|
def match 0 =match
|
|
|
|
def bytes expected:to-bytes =bytes
|
|
|
|
[
|
|
|
|
while { match bytes:len eq not } {
|
|
|
|
iter:next dup (match bytes:get) eq dup if {
|
|
|
|
match ++ =match
|
|
|
|
} not if {
|
|
|
|
0 =match
|
|
|
|
}
|
|
|
|
}
|
|
|
|
{ | pop pop } match:foreach
|
|
|
|
] _str
|
2023-03-06 03:45:16 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2023-03-06 04:28:51 +01:00
|
|
|
construct net:http:Response {
|
2023-03-06 14:56:49 +01:00
|
|
|
version
|
2023-03-06 03:45:16 +01:00
|
|
|
state-num state-msg
|
|
|
|
headers
|
|
|
|
body
|
|
|
|
;
|
|
|
|
construct { this | with this ;
|
2023-03-06 14:56:49 +01:00
|
|
|
MicroMap:new this:=headers
|
2023-03-06 03:45:16 +01:00
|
|
|
"" this:=body
|
|
|
|
this
|
|
|
|
}
|
2023-03-06 14:56:49 +01:00
|
|
|
read-from-bytes { this | with bytes this ;
|
|
|
|
use net:http:help
|
|
|
|
bytes:iter =bytes
|
|
|
|
"HTTP/" bytes help:assert-str
|
|
|
|
" " bytes help:until-str this:=version
|
|
|
|
" " bytes help:until-str _mega this:=state-num
|
|
|
|
"\r\n" bytes help:until-str this:=state-msg
|
|
|
|
while { "\r\n" bytes help:until-str dup "" eq not } {
|
|
|
|
def iter ": " swap:split:iter =iter
|
|
|
|
(
|
|
|
|
iter:next ": "
|
|
|
|
iter:join
|
|
|
|
) this:headers:set;
|
|
|
|
} pop
|
|
|
|
0 ("Content-Length" this:headers:get _mega) bytes:collect:sub this:=body
|
|
|
|
this
|
|
|
|
}
|
|
|
|
content-type { str | with this ;
|
|
|
|
"Content-Type" this:headers:get
|
|
|
|
}
|
2023-03-06 03:45:16 +01:00
|
|
|
}
|