Question
· Jan 31, 2023

Reading large stream from %CSP.Request

We have created a number of REST adapters that extend %CSP.REST and these have been working fine.  However, we are now facing a problem with a new one where very large XML documents are being posted.  This is the pattern we are following:

Set inMsg = %request.Content.Read()

Set tSC = ##class(Ens.Director).CreateBusinessService("Epro_ItkHttp",.tBusinessService)

Set tSC = tBusinessService.ProcessInput(inMsg, .tBusinessServiceOutput)

However, when the %request is particularly long, it is being truncated, and working with %XML.Reader then fails in the business service class.

I believe the call to Read() is the problem.  If I call it with some arbitrarily long value - such as Read(500000) - then it works.

What is the correct approach here?  Is there any harm in putting in a massive number into the len parameter of the Read() method?  Or is there a way of looping through the stream and constructing the object to pass to the business service?

Any advice much appreciated.

Product version: IRIS 2022.1
$ZV: IRIS for Windows (x86-64) 2022.1 (Build 209U) Tue May 31 2022 12:16:40 EDT [HealthConnect:3.5.0] [HealthConnect:3.5.0]
Discussion (4)2
Log in or sign up to continue

Is there any harm in putting in a massive number into the len parameter of the Read() method?

You cannot read more than 3641144 characters from a stream to a string, as this is the limit for long strings: String Length Limit

From the documentation for the Read() method:

If no len is passed in, ie. 'Read()' then it is up to the Read implementation as to
how much data to return. Some stream classes use this to optimize the amount of
data returned to align this with the underlying storage of the stream.

So you can write like this:
Set inMsg %request.Content.Read($$$MaxLocalLength)

Macros are defined in %msql.inc:

#define MaxStringLength 3641144
#define MaxLocalLength $zutil(96,39)

Thanks for your reply, makes complete sense.  I wasn't aware of $$$MaxLocalLength.

On looking into this further, it turns out I don't need to Read() at all.  Just passing the %request.Content on like this:

Set tSC tBusinessService.ProcessInput(%request.Content, .tBusinessServiceOutput)

Does the trick.  Then in the business service class, using the OpenStream() method of %XML.Reader behaves as expected when deserialising to the class objects.