Question
· Apr 27, 2023

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
Discussion (7)3
Log in or sign up to continue

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

ClassMethod test() As %Status
{
  #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 -

HS.FHIRServer.RestHandler:marshallRequestFromHttp()

    // 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:

EnsLib.HTTP.Service:addAttributesToBody()

    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 = 1ElseIf 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.