How to process “multipart/form-data” message submitted to BTSHttpReceive.dll


 


 




When use a form based web page as the below to submit a XML file to one BizTalk HTTP receive location using XMLReceive pipeline, It would fail to validate and suspended.


 


 


<html>


<body>


<FORM NAME="myForm" ACTION="http://localhost/btarnhttpreceive/btshttpreceive.dll?httpmime" ENCTYPE="multipart/form-data" METHOD="post">


<INPUT TYPE="file" NAME="myFile" >


<INPUT TYPE="submit" VALUE="Upload File" >


</FORM >


</body>


</html>


 


If check the suspended message, you would see the message format similar as the below:


 


-----------------------------7d91593580102


Content-Disposition: form-data; name="myFile"; filename="D:\HttpMimeTest\1.xml"


Content-Type: text/xml


 


<ns0:TestRoot xmlns:ns0="http://HttpMimeTest.Schema1">


  <TestRecord>


    <TestField>TestField_0</TestField>


  </TestRecord>


</ns0:TestRoot>


-----------------------------7d91593580102—


 


It looks like a MIME encoded message, but if develop a customized pipeline which add a MIME/SMIME decoder before the XML disassembler, it would fail to decode the message since actually the format is not complete/standard MIME format.


 


 


Solution:


 


Develop a pipeline component which is added before the MIME/SMIME decoder at the same stage, the component would add the missed MIME header as the below to the beginning of an incoming message to construct a complete MIME message so the MIME/SMIME decoder can decode it, retrieve the packed XML and pass it to the XML disassembler at the next stage in the pipeline.


 


 


MIME-Version: 1.0


Content-Type: multipart/form-data; boundary=---------------------------7d91593580102


 


 


The FixMsg pipeline component sample which is located at the folder [BizTalk Installation Folder] \ SDK\Samples\Pipelines\CustomComponent\FixMsg can be used to add a fixed preconfigured string to the beginning of a message. It has to be modified in order to add a dynamic string such as boundary part as the above. The trick is the Content-Type including boundary can be retrieved from the incoming message context property InboundHttpHeaders. The following is the demo modified function Execute in the FixMsg.cs which read the Content-Type head with boundary from the context property InboundHttpHeaders and then append it to the preconfigured prependData which is “MIME-Version: 1.0”.


 


 


        public IBaseMessage Execute(IPipelineContext pc, IBaseMessage inmsg)


        {


            IBaseMessagePart bodyPart = inmsg.BodyPart;


            if (bodyPart!=null)


            {


                byte[] prependByteData  = ConvertToBytes(prependData);


                byte[] appendByteData   = ConvertToBytes(appendData);


 


                string headersString = inmsg.Context.Read("InboundHttpHeaders", "http://schemas.microsoft.com/BizTalk/2003/http-properties").ToString();


                string[] headers = headersString.Split(new Char[] {'\r','\n' }, StringSplitOptions.RemoveEmptyEntries);


                string MimeHead=String.Empty;


                bool Foundit=false;


                for (int i=0;i<headers.Length;i++)


                {


                    if (headers[i].StartsWith("Content-type:", true, null))


                    {


                        MimeHead = headers[i];


                        Foundit = true;


                        break;


                    }


                }


                if (Foundit)


                {


                    StringBuilder sb = new StringBuilder();


                    sb.Append(prependData);


                    sb.Append("\r\n");


                    sb.Append(MimeHead);


                    sb.Append("\r\n");


                    prependByteData = ConvertToBytes(sb.ToString());


                }


 


                   Stream originalStrm            = bodyPart.GetOriginalDataStream();


                   Stream strm = null;


 


                   if (originalStrm != null)


                   {


                             strm             = new FixMsgStream(originalStrm, prependByteData, appendByteData, resManager);


                             bodyPart.Data    = strm;


                             pc.ResourceTracker.AddResource( strm );


                   }


            }


           


            return inmsg;


        }


 


The following is the screen capture for the customized pipeline project.


 pipe.JPGpipeprop.JPG


 


Regards,


XiaoDong Zhu 


 


 

Comments (1)

  1. Anu says:

    Very very clear and helpful! thanks a lot! Saved Me a lot of time and trouble!!!

    Minor change that I had to make was modify 'Content-type:' to 'Content-Type:' in the code modification.Thanks a lot!

Skip to main content