Skip to content

Commit c65eb03

Browse files
authored
Merge pull request #859 from refaktor/dotwords
improving https server api
2 parents f816ddd + 4a281d6 commit c65eb03

2 files changed

Lines changed: 202 additions & 0 deletions

File tree

evaldo/builtins_http.go

Lines changed: 179 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -296,6 +296,43 @@ var Builtins_http = map[string]*env.Builtin{
296296
},
297297
},
298298

299+
// Example:
300+
// ; Inside a handler: w .Add-header 'set-cookie "a=1; Path=/; HttpOnly"
301+
// ; Inside a handler: w .Add-header 'vary "Accept-Encoding"
302+
// Args:
303+
// * writer: Native Go-server-response-writer object from HTTP handler
304+
// * name: Word representing the header name (e.g., 'set-cookie, 'vary)
305+
// * value: String value to add for the header
306+
// Returns:
307+
// * the response writer object for method chaining
308+
"Go-server-response-writer//Add-header": {
309+
Argsn: 3,
310+
Doc: "Adds a custom HTTP header value in the response, preserving existing values for multi-value headers.",
311+
Fn: func(ps *env.ProgramState, arg0 env.Object, arg1 env.Object, arg2 env.Object, arg3 env.Object, arg4 env.Object) env.Object {
312+
switch writer := arg0.(type) {
313+
case env.Native:
314+
switch name := arg1.(type) {
315+
case env.Word:
316+
name_ := ps.Idx.GetWord(name.Index)
317+
switch value := arg2.(type) {
318+
case env.String:
319+
writer.Value.(http.ResponseWriter).Header().Add(name_, value.Value)
320+
return arg0
321+
default:
322+
ps.FailureFlag = true
323+
return MakeArgError(ps, 3, []env.Type{env.StringType}, "Go-server-response-writer//Add-header")
324+
}
325+
default:
326+
ps.FailureFlag = true
327+
return MakeArgError(ps, 2, []env.Type{env.WordType}, "Go-server-response-writer//Add-header")
328+
}
329+
default:
330+
ps.FailureFlag = true
331+
return MakeArgError(ps, 1, []env.Type{env.NativeType}, "Go-server-response-writer//Add-header")
332+
}
333+
},
334+
},
335+
299336
// Example:
300337
// ; Inside a handler: w .Write-header 404
301338
// ; Inside a handler: w .Write-header 200
@@ -493,6 +530,148 @@ var Builtins_http = map[string]*env.Builtin{
493530
},
494531
},
495532

533+
// Example:
534+
// ; Inside a handler: req .Header? "authorization"
535+
// ; Inside a handler: req .Header? "content-type"
536+
// Args:
537+
// * request: Native Go-server-request object from HTTP handler
538+
// * name: String header name to retrieve (e.g., "authorization", "content-type")
539+
// Returns:
540+
// * string header value (empty string if header is missing)
541+
"Go-server-request//Header?": {
542+
Argsn: 2,
543+
Doc: "Gets a header value from the HTTP request by name.",
544+
Fn: func(ps *env.ProgramState, arg0 env.Object, arg1 env.Object, arg2 env.Object, arg3 env.Object, arg4 env.Object) env.Object {
545+
switch req := arg0.(type) {
546+
case env.Native:
547+
switch name := arg1.(type) {
548+
case env.String:
549+
val := req.Value.(*http.Request).Header.Get(name.Value)
550+
return *env.NewString(val)
551+
default:
552+
ps.FailureFlag = true
553+
return MakeArgError(ps, 2, []env.Type{env.StringType}, "Go-server-request//header?")
554+
}
555+
default:
556+
ps.FailureFlag = true
557+
return MakeArgError(ps, 1, []env.Type{env.NativeType}, "Go-server-request//header?")
558+
}
559+
},
560+
},
561+
562+
// Example:
563+
// ; Inside a handler: creds: req .Basic-auth?
564+
// ; user: creds |first
565+
// ; pass: creds |second
566+
// Args:
567+
// * request: Native Go-server-request object from HTTP handler
568+
// Returns:
569+
// * block with username and password strings when Basic Auth is present
570+
// * error when Basic Auth credentials are missing
571+
"Go-server-request//Basic-auth?": {
572+
Argsn: 1,
573+
Doc: "Gets HTTP Basic Authentication credentials from the request as [username password].",
574+
Fn: func(ps *env.ProgramState, arg0 env.Object, arg1 env.Object, arg2 env.Object, arg3 env.Object, arg4 env.Object) env.Object {
575+
switch req := arg0.(type) {
576+
case env.Native:
577+
username, password, ok := req.Value.(*http.Request).BasicAuth()
578+
if !ok {
579+
ps.FailureFlag = true
580+
return MakeBuiltinError(ps, "Basic auth credentials are missing.", "Go-server-request//basic-auth?")
581+
}
582+
pair := make([]env.Object, 2)
583+
pair[0] = *env.NewString(username)
584+
pair[1] = *env.NewString(password)
585+
return *env.NewBlock(*env.NewTSeries(pair))
586+
default:
587+
ps.FailureFlag = true
588+
return MakeArgError(ps, 1, []env.Type{env.NativeType}, "Go-server-request//basic-auth?")
589+
}
590+
},
591+
},
592+
593+
// Example:
594+
// ; Inside a handler: req .Method?
595+
// ; equal { req .Method? } "GET"
596+
// Args:
597+
// * request: Native Go-server-request object from HTTP handler
598+
// Returns:
599+
// * string containing HTTP method (GET, POST, PUT, DELETE, ...)
600+
"Go-server-request//Method?": {
601+
Argsn: 1,
602+
Doc: "Gets the HTTP request method.",
603+
Fn: func(ps *env.ProgramState, arg0 env.Object, arg1 env.Object, arg2 env.Object, arg3 env.Object, arg4 env.Object) env.Object {
604+
switch req := arg0.(type) {
605+
case env.Native:
606+
return *env.NewString(req.Value.(*http.Request).Method)
607+
default:
608+
ps.FailureFlag = true
609+
return MakeArgError(ps, 1, []env.Type{env.NativeType}, "Go-server-request//method?")
610+
}
611+
},
612+
},
613+
614+
// Example:
615+
// ; Inside a handler: body: req .Read-body
616+
// ; Inside a handler: print body
617+
// Args:
618+
// * request: Native Go-server-request object from HTTP handler
619+
// Returns:
620+
// * string containing the request body
621+
"Go-server-request//Read-body": {
622+
Argsn: 1,
623+
Doc: "Reads the HTTP request body as a string.",
624+
Fn: func(ps *env.ProgramState, arg0 env.Object, arg1 env.Object, arg2 env.Object, arg3 env.Object, arg4 env.Object) env.Object {
625+
switch req := arg0.(type) {
626+
case env.Native:
627+
data, err := io.ReadAll(req.Value.(*http.Request).Body)
628+
if err != nil {
629+
ps.FailureFlag = true
630+
return MakeBuiltinError(ps, err.Error(), "Go-server-request//read-body")
631+
}
632+
return *env.NewString(string(data))
633+
default:
634+
ps.FailureFlag = true
635+
return MakeArgError(ps, 1, []env.Type{env.NativeType}, "Go-server-request//read-body")
636+
}
637+
},
638+
},
639+
640+
// Example:
641+
// ; Inside a handler: req .Headers?
642+
// ; Inside a handler: req .Headers? |print
643+
// Args:
644+
// * request: Native Go-server-request object from HTTP handler
645+
// Returns:
646+
// * dict containing all request headers
647+
"Go-server-request//Headers?": {
648+
Argsn: 1,
649+
Doc: "Gets all HTTP request headers as a dictionary.",
650+
Fn: func(ps *env.ProgramState, arg0 env.Object, arg1 env.Object, arg2 env.Object, arg3 env.Object, arg4 env.Object) env.Object {
651+
switch req := arg0.(type) {
652+
case env.Native:
653+
headers := make(map[string]any)
654+
for key, values := range req.Value.(*http.Request).Header {
655+
if len(values) == 0 {
656+
headers[key] = ""
657+
} else if len(values) == 1 {
658+
headers[key] = values[0]
659+
} else {
660+
vals := make([]env.Object, len(values))
661+
for i, v := range values {
662+
vals[i] = *env.NewString(v)
663+
}
664+
headers[key] = *env.NewBlock(*env.NewTSeries(vals))
665+
}
666+
}
667+
return *env.NewDict(headers)
668+
default:
669+
ps.FailureFlag = true
670+
return MakeArgError(ps, 1, []env.Type{env.NativeType}, "Go-server-request//headers?")
671+
}
672+
},
673+
},
674+
496675
// Example:
497676
// ; Inside a handler: url: req .Url?
498677
// ; equal { url .type? } 'native

evaldo/builtins_io.go

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1488,6 +1488,29 @@ var Builtins_io = map[string]*env.Builtin{
14881488
},
14891489
},
14901490

1491+
// Args:
1492+
// * response: native https-response object
1493+
// Returns:
1494+
// * empty string if close succeeds
1495+
"https-response//Close-body!": {
1496+
Argsn: 1,
1497+
Doc: "Closes the HTTPS response body to free network resources.",
1498+
Fn: func(ps *env.ProgramState, arg0 env.Object, arg1 env.Object, arg2 env.Object, arg3 env.Object, arg4 env.Object) env.Object {
1499+
switch resp := arg0.(type) {
1500+
case env.Native:
1501+
err := resp.Value.(*http.Response).Body.Close()
1502+
if err != nil {
1503+
ps.FailureFlag = true
1504+
return MakeBuiltinError(ps, err.Error(), "https-response//Close-body!")
1505+
}
1506+
return *env.NewString("")
1507+
default:
1508+
ps.FailureFlag = true
1509+
return MakeArgError(ps, 1, []env.Type{env.NativeType}, "https-response//Close-body!")
1510+
}
1511+
},
1512+
},
1513+
14911514
//
14921515
// ##### Email Operations ##### "Email sending and SMTP communication"
14931516
//

0 commit comments

Comments
 (0)