Class ::nsmcp::HttpTransport (public)

 ::nx::Class ::nsmcp::HttpTransport[i]

Defined in /usr/local/ns/tcl/nsmcp/lib/transport.tcl

Testcases:
No testcase defined.
Source code:
    :property authenticator:required
    :property protocol:required
    :property {allowedOrigins {}}
    :property {maxBodyBytes:integer 65536}
    :public method response {status body {headers {}}} {
        return [dict create status $status body $body headers $headers]
    }
    :public method mediaTypes {header} {
        set types {}
        foreach part [split [string tolower $header] ,] {
            lappend types [string trim [lindex [split $part \;] 0]]
        }
        return $types
    }
    :public method request {method headers body server} {
        # Header dictionary uses lower-case keys; created by Server.http.
        try {
            if {[dict exists $headers origin] &&
                [dict get $headers origin] ni ${:allowedOrigins}} {
                return [:response 403 "Origin not permitted"]
            }
            set authorization {}
            if {[dict exists $headers authorization]} {set authorization [dict get $headers authorization]}
            if {[catch {${:authenticator} authenticate $authorization $server} context options]} {
                set ec [dict get $options -errorcode]
                if {[lrange $ec 0 1] eq {NSMCP HTTP}} {
                    return [:response [lindex $ec 2] "Authentication required"  [dict create WWW-Authenticate {Bearer realm="nsmcp"}]]
                }
                ns_log error "nsmcp: authentication adapter failed"
                return [:response 500 "Internal error"]
            }
            if {$server ni [$context targets]} {return [:response 403 "Target not permitted"]}
            if {$method ne "POST"} {return [:response 405 "Method not allowed" [dict create Allow POST]]}
            if {[dict exists $headers mcp-protocol-version] &&
                ![${:protocol} supports [dict get $headers mcp-protocol-version]]} {
                return [:response 400 "Unsupported protocol version"]
            }
            if {![dict exists $headers content-type] ||
                [:mediaTypes [dict get $headers content-type]] ne {application/json}} {
                return [:response 415 "Expected application/json"]
            }
            if {![dict exists $headers accept]} {return [:response 406 "Missing Accept header"]}
            set accepted [:mediaTypes [dict get $headers accept]]
            if {"application/json" ni $accepted || "text/event-stream" ni $accepted} {
                return [:response 406 "Accept must include application/json and text/event-stream"]
            }
            if {[string length [encoding convertto utf-8 $body]] > ${:maxBodyBytes}} {
                return [:response 413 "Request body too large"]
            }
            set response [${:protocol} handle $context $body]
            dict set response headers [dict create Content-Type {application/json; charset=utf-8}]
            ns_log debug "nsmcp: principal=[ns_json value -type string -- [$context principal]] target=[ns_json value -type string -- $server] status=[dict get $response status]"
            return $response
        } finally {
            # Immediate cleanup plus the deallocate hook as a fallback for aborts.
            ::nsmcp::cleanup
        }
    }
    :public method maxBodyBytes {} {return ${:maxBodyBytes}}
XQL Not present:
Generic, PostgreSQL, Oracle
[ hide source ] | [ make this the default ]
Show another procedure: