IRIS/REST, how could I get all HTTP headers?
It is clear how to get the request header value with a specific name:
Class My.RestController Extends %CSP.REST
{
ClassMethod processRequest() As %Status
{
#dim request as %CSP.Request
set request = %request
set h = ##class(%REST.Impl).%GetHeader("...")
...
return $$$OK
}
But I can't figure out how to enumerate ALL the request headers (and also get all values).
Product version: IRIS 2023.1
all headers are stored in the %request.CgiEnvs("HTTP"_xxxxx)
You may do something like this in the OnPreHTTP method in your CSP page:
S a="" F { S a=$O(%request.CgiEnvs(a)) Q:a="" If $E(a,1,4)="HTTP" Set ^yourGlobal(a)=%request.CgiEnvs(a) }
Check this article.
One of the most simple options - a CSP utility method which outputs all objects as a response. Just add this to any part of your code:
Thanks for the hint with the DispayAllObjects method but I see that it malforms the names of the original HTTP headers. Thus, the "User-Agent" header becomes "HTTP_USER_AGENT" and so on.
Let me clarify - I'm also trying to implement a kind of proxy REST service which accepts an original web request and forwards that request to some another REST service behind, keeping all the original HTTP headers. Perhaps there is some other way to do it?
Hi @Alex Baumberg !
First, if you just want to send an HTTP Request from one point to another you can use the HTTP Passthrough mechanism.
And see also my comment to Dmitrii's reply below.
In addition if you are focusing on FHIR requests (as I assume you are, per prior knowledge 😉) you can consider using the FHIR Interoperability Adapter mechanism where you will have a "digested" request which already includes all the HTTP Headers in the AdditionalInfo array.
Finally, I've implemented the following brute solution. I don't like the look of this at all, but it works
{
#dim request as %CSP.Request
set request = %request
#dim headerName as %String
set headerName = ""
set headerName = request.NextCgiEnv(headerName)
while (headerName '= "") {
if $find(headerName, "HTTP_") '= 0 {
set localHeaderName = $replace(headerName, "HTTP_", "")
set localHeaderName = $replace(localHeaderName, "_", "- ")
set localHeaderName = $zconvert(localHeaderName, "L")
set localHeaderName = $zconvert(localHeaderName, "W")
set localHeaderName = $replace(localHeaderName, "- ", "-")
write localHeaderName, ": ", request.GetCgiEnv(headerName), !
}
set headerName = request.NextCgiEnv(headerName)
}
return $$$OK
}
Hi @Dmitrii Baranov
You can take a peak at a similar task performed internally in the FHIR Server REST handler class -
// For compatability, copy all HTTP_ headers into the AdditionalInfo section of the request Set tKey = "" For { Set tKey = $ORDER(%request.CgiEnvs(tKey)) Quit:tKey="" If tKey?1"HTTP_"1.E { // Determine the proper header name (will be all caps unfortunately) Set tHeader = $PIECE(tKey,"HTTP_",2,*) // Copy the HTTP headers - except for certain ones. If (tHeader '= "AUTHORIZATION") { Do pRequest.AdditionalInfo.SetAt(%request.CgiEnvs(tKey), "HEADER:"_tHeader) } } }
Note this is internal code.
You can also similar code for the Generic HTTP Service (used by the Passthrough I mentioned to Alex above), from:
Set tattrH=$O(%request.CgiEnvs("HTTP_")) While $E(tattrH,1,5)="HTTP_" { If tattrH'="HTTP_URL",tattrH'="HTTP_VERSION" { Set attr=$REPLACE($E(tattrH,6,*),"_","-"), lwrattr=$ZCVT(attr,"L") If '((lwrattr="transfer-encoding")&&($ZCVT(%request.CgiEnvs(tattrH),"L")="chunked")),'((lwrattr="content-encoding")&&($ZCVT(%request.CgiEnvs(tattrH),"L")="gzip")) { Set:..#TOLOWERHEADERVARS attr=lwrattr Set:'$D(lwrattrs(lwrattr)) pStream.Attributes(attr)=%request.CgiEnvs(tattrH), lwrattrs(lwrattr)="" Set:"content-length"=lwrattr tLen=pStream.Attributes(attr) Set:"content-type"=lwrattr tContentType=pStream.Attributes(attr) } ElseIf (lwrattr="content-encoding") { Set tgzip = 1 } ElseIf tLen = "x" { Set tLen="xchunked" } } Set tattrH=$O(%request.CgiEnvs(tattrH)) }
Again this is internal code.
But coming back to my comment to Alex above, I would recommend using one of the approaches I mentioned there (the Generic Passthrough service, or the FHIR Interop. built-in service) and this way all of the above is already handled for you.
Hi Tani, and thank you (again) for your valuable tips! The generic passthrough is an option.