Question
· Feb 24

Reading HTTP multipart/form messages from EnsLib.HTTP.GenericMessage object.

Hello everyone!

I have set up an EnsLib.REST.GenericService with an  EnsLib.HTTP.InboundAdapter which forwards the http requests received by a web app to my Business Process. 

I would like to parse HTTP multipart/form messages I am receving and be able to iterate over the various fields within the request body, accessing its content type and the content itself.

As far as I understand I should use the %Net.MIMEReader class which should return a list of %Net.MIMEPart, one for each field within the request. However if I do : 

Set mimeReader = ##class(%Net.MIMEReader).%New()
Set sc = mimeReader.OpenStream(pRequest.Stream)
Set sc = mimeReader.ReadMIMEMessage(.message)
Set parts = message.Parts.Count()

 

it results that the number of Parts is zero, Even though I am sending a request with postman containing two fields. This is how it looks like:

POST ....
Host: localhost:1888
Content-Length: 290
Content-Type: multipart/form-data; boundary=----WebKitFormBoundary7MA4YWxkTrZu0gW

------WebKitFormBoundary7MA4YWxkTrZu0gW
Content-Disposition: form-data; name="first field"
Content-Type: text/plain

Test text
------WebKitFormBoundary7MA4YWxkTrZu0gW
Content-Disposition: form-data; name="third field"
Content-Type: text/plain

Test text 2
------WebKitFormBoundary7MA4YWxkTrZu0gW--

If anyone as any clue on how to handle this case suggestions will be much appreciated!

Discussion (4)1
Log in or sign up to continue
    set bii=$p(pStreamIn.GetAttribute("content-type"),"=",2)
	set message=##class(%Net.MIMEPart).%New()
	set reader=##class(%Net.MIMEReader).%New()
	Do reader.OpenStream(pStreamIn)
	set a=0
	while a'=1
	{
		Set sc=reader.readHeader(.message,1)
	    Set sc=reader.readBody(message,bii,.a)
	    $$$LOGINFO(message.GetHeader("Content-Type"))
	    $$$LOGINFO($p(message.GetHeader("Content-Disposition"),"""",2))
	    $$$LOGINFO(message.Body.Read())
	}

Hi, thank you for your answer! Your solution somehow acess the content of the message but not how one would expect. By using as a reference the request I posted in my question the output of your code are three logs:

  • 1st: text/plain
  • 2nd: first field
  • 3rd: "
    test----------------------------968066144412655705281003 Content-Disposition: form-data; name="third field" Content-Type: text/plain test 2 ----------------------------968066144412655705281003--"

It seems like the code is reading everything after the header of the first field of the multipart message as the body, not using the boundary properly. In fact, the first line of yout code retrieves only an empty string. I have tried to modify your code to actually access the boundary by doing Set bii = message.BoundaryGet() in the second line of the while. But then I got an <INVALID OREF> when trying to read the body.

 The logs were the ones I wrote in my previous response, however I found the solution to be this one:

set boundary = $PIECE(pRequest.HTTPHeaders.GetAt("content-type"),"boundary=",2)
Set reader = ##class(%Net.MIMEReader).%New()
Set sc = reader.OpenStream(pRequest.Stream)
If $$$ISERR(sc) {
    $$$LOGERROR("Failed to open stream: "_$System.Status.GetErrorText(sc))
    Quit
}
set a=0
while a'=1 {
   Set sc=reader.readHeader(.message,1)
   $$$LOGINFO(message.GetHeader("Content-Type"))
   $$$LOGINFO($p(message.GetHeader("Content-Disposition"),"""",2))
   Set sc=reader.readBody(message,boundary,.a)
   Set body = message.Body.Read()
   $$$LOGINFO(body)
}

The key was to correctly retrieve the boundry in the first place. 

Thank you again for your solution which turned out to be correct!