DataPower

DataPower

Join this online group to communicate across IBM product users and experts by sharing advice and best practices with peers and staying up to date regarding product enhancements.

 View Only
  • 1.  Send multipart/form-data in XST

    Posted Wed March 15, 2023 10:36 AM

    Hi Team, 

    I'm trying to send a send a text file as multipart/form-data to the backend system over https protocol through an XSLT but unfortunately it's not working as expected. Can you please help me on this? Please find the XSLT that I'm using to send the data

    <?xml version="1.0" encoding="UTF-8"?>

    <xsl:stylesheet
        xmlns:dp="http://www.datapower.com/extensions"
        xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
        extension-element-prefixes="dp"
        exclude-result-prefixes="dp"
        version="1.1">
        
        <xsl:template match="/">

                  <!-- SETTING CONTENT TYPE ON A CONTEXT VARIABLE -->
          <!--        <xsl:variable name="URI" select="dp:variable('var://service/URI')" />
              <xsl:variable name="ContentType" select="dp:request-header('Content-Type')" />
                  <xsl:variable name="TransID" select="dp:request-header('TransactionID')" /> -->
                   
                    <xsl:variable name="URI" select="'/services/v1/POSSalesReturns'" />
                    <xsl:variable name="TransID" select="dp:request-header('TransactionID')" /> 
                  
             <!--  <dp:set-variable name="'var://context/request/contenttype'" value="$ContentType" /> -->
                   <dp:set-variable name="'var://context/request/URI'" value="$URI" />
                    <dp:set-variable name="'var://context/request/transid'" value="$TransID" />

                   <!-- FETCHING THE SUBSCRIPTION XML --> 
                    <xsl:variable name="Subscrip" select="document('Subscription_New.xml')" />

            <xsl:variable name="Subs" select="$Subscrip/Subscription/Interface/Key[../URI/text()=$URI]" />
                    <xsl:variable name="Trace" select="$Subscrip/Subscription/Interface/Trace[../URI/text()=$URI]" />
                    <xsl:variable name="Source" select="$Subscrip/Subscription/Interface/Name[../URI/text()=$URI]" />
                    <dp:set-variable name="'var://context/route/source'" value="$Source" />
                    
            <!-- SETTING THE HEADERS FOR REQUEST         
            <dp:set-http-request-header name="'Ocp-Apim-Subscription-Key'" value="$Subs" />
                    <dp:set-http-request-header name="'Ocp-Apim-Trace'" value="$Trace" /> -->
               <!--    <xsl:if test="string-length($ContentType) !=0">
                      <dp:set-http-request-header name="'ContentType'" value="$ContentType" />
                   </xsl:if>
                    <xsl:if test="string-length($ContentType) =0">
                      <dp:set-http-request-header name="'ContentType'" value="'multipart/form-data; boundary=974767299852498929531610575'" />
                   </xsl:if> -->
                <!--   <dp:set-http-request-header name="'Content-Type'" value="'multipart/form-data; boundary=123'" />
                   <dp:set-http-request-header name="'User-Agent'" value="'IBM'" /> -->
                   
            <!--        <xsl:variable name="httpHeaders">
                        <header name="Ocp-Apim-Subscription-Key" value="$Subs" />
                        <header name="Ocp-Apim-Trace" value="$Trace" />
                    </xsl:variable> -->
                    
                    <xsl:variable name="httpHeaders">
                        <header name="Ocp-Apim-Subscription-Key">85771ef19f4046ae8af0d2a3258d33b8</header>
                        <header name="Ocp-Apim-Trace">true</header>
                    </xsl:variable>
                
                   <!--    <xsl:message dp:priority="debug">
                       httpHeaders:<xsl:value-of select="$http-request-header"/>
                    </xsl:message>    -->
             <xsl:variable name="wholeUrl">https://stag-api.asda.uk/external/ukil/v1/posinbound</xsl:variable>        
             <xsl:message dp:priority="debug">
            wholeUrl:<xsl:value-of select="$wholeUrl"/>
        </xsl:message>
        
        <xsl:variable name="Mime" select="dp:variable('var://context/payload/multipart')" />
        <xsl:variable name="binFlow" select="dp:encode($Mime,'base-64')"/>
        <xsl:variable name="MIMEPayload">
            <dp:set-mime-header name="MIME-version" value="'1.0'" />
            <dp:set-mime-header name="Content-Type" value="'multipart/related;boundary=Boundary;type=text/xml'" />
            <dp:set-mime-header name="Content-Id" value="'part one'" />
            <xsl:copy-of select="$binFlow" />
        </xsl:variable>
         
         <xsl:message dp:priority="debug">
         PayloadFinal:::  <xsl:value-of select="$MIMEPayload"/>
         </xsl:message>
         
         <xsl:variable name="DummyResponse">
        <dp:url-open target="https://10.55.176.113:7813/multipart/poc" response="responsecode-binary" 
        timeout="60" 
        http-method="post" 
        http-headers="$httpHeaders"
        content-type = "multipart/related;boundary=Boundary"
        ssl-proxy="client:sslp_DPSSLClient_Forward"> 
        <xsl:copy-of select="$MIMEPayload"/>
        </dp:url-open>
        </xsl:variable>
        <xsl:message dp:priority="debug">
            DummyResponse:<xsl:value-of select="$DummyResponse"/>
        </xsl:message>
        <xsl:variable name="decodedResponse1">
            <xsl:copy-of select="dp:decode( dp:binary-encode($DummyResponse/result/binary/node()), 'base-64' )" />
        </xsl:variable>             
            <xsl:message dp:priority="debug">
            decodedResponse1:<xsl:value-of select="$decodedResponse1"/>
        </xsl:message>        
                </xsl:template>
            </xsl:stylesheet>

     

      Can you please let me know what additional changes that I need to do to make it working?

     



    ------------------------------
    Debarpan Mukhopadhyay
    ------------------------------


  • 2.  RE: Send multipart/form-data in XST

    Posted Thu March 16, 2023 04:35 AM

    Hi,

    haven't done this using XSLT because using GWScript is a lot easier. Anyway, just check that you have all the boundaries etc, in place. Here is an example GWScript for creating a multipart/related message "manually" to get an idea on the structure of the message. The message is a SWA but if you'll strip the SOAP message part it should be ok.

    var hm = require('header-metadata');

    session.input.readAsBuffer(function (error, buffer) {
        if (error)
        {
            // handle error
            session.output.write (error.errorMessage);
          } else {
                //Create a boundary id
                var boundary = "xyz123";
                
                //Line break
                var crlf = '\r\n';
                
                //Create a soap message payload
                var soap_message = '<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/"><soapenv:Body><foo>the soap message body part goes here</foo></soapenv:Body></soapenv:Envelope>';
                
                //Create the multipart message payload
                var multipart = '--' + boundary + crlf + 
                                'Content-Type: text/xml' + crlf + crlf + 
                                soap_message + crlf + '--' + boundary + crlf + 
                                'Content-Type: application/zip' + crlf +
                                'Content-Transfer-Encoding: base64' + crlf +
                                'Content-ID: <myattachment>' + crlf + crlf + 
                                buffer.toString('base64') + crlf + '--' + boundary + '--' + crlf;
                
                //Concatenate a new content-type header value
                var contentType = 'multipart/related; boundary=' + boundary + ' type="text/xml"';
                
                //Set the content type header created above
                hm.current.set('Content-Type', contentType);

                //Write payload into output
                session.output.write(multipart);
          }
    });



    ------------------------------
    Hermanni Pernaa
    ------------------------------



  • 3.  RE: Send multipart/form-data in XST

    Posted Thu June 01, 2023 04:42 AM

    Thank you very much for this. I have tried with the below code and it worked for me.

    var hm = require('header-metadata');
     
    session.input.readAsBuffer(function (error, buffer) {
     
    if (error)
     
    {
     
    session.output.write (error.errorMessage);
     
    } else {
     
    //Create a boundary
     
    var boundary = "xyz123";
     
    //Line break syntax
     
    var crlf = '\r\n';
     
    //Create the multipart message payload
     
    var multipart = '--' + boundary + crlf +
     
    'Content-Disposition: form-data; name="file"; filename="payload.txt"' + crlf +
     
    'Content-Type: text/plain' + crlf + crlf +
     
    buffer.toString() + crlf + '--' + boundary + '--' + crlf;
     
    //Concatenate a new content-type header value
     
    var contentType = 'multipart/form-data; boundary=' + boundary + ' type="text/plain"';
     
    //Set the content type in http requst header
     
    hm.current.set('Content-Type', contentType);
     
    //Write the output payload
     
    session.output.write(multipart);
     
    }
     
    });
    Thanks,
    Debarpan 

     



    ------------------------------
    Debarpan Mukhopadhyay
    ------------------------------



  • 4.  RE: Send multipart/form-data in XST

    Posted Thu March 16, 2023 09:10 AM
    Edited by Hermann Stamm-Wilbrandt Thu March 16, 2023 09:11 AM

    There is no "1.1" XSLT version support, DataPower has an XSLT 1.0 compiler.

    You should send what you create against a localhost HTTP service in echo mode, and make MPGW response type passthru. 
    That way you can store what you create into a file for inspection.
    Under Linux "od -Ax -tx1 file" or using hexedit then allows to investigate.

    I created bash script that sends a binary file as (dummy) SOAP with attachments for playing with DataPower:

    $ cat mimeswacurl 
    #!/bin/bash
     
    boundary=epoch-`date +%s`
     
    echo "--$boundary 
    Content-Type: application/soap+xml
    Content-Location: root
     
    <env:Envelope xmlns:env=\"http://schemas.xmlsoap.org/soap/envelope/\">
    <env:Body>
    <some_soap/>
    </env:Body>
    
    </env:Envelope>
    --$boundary
    Content-Type: `java -classpath ~/bin MimeType $1`
    Content-Transfer-Encoding: binary
    Content-Id: <binary>
     
    " `cat $1` "
    --$boundary--
    " | curl -s --data-binary @- -H 'Content-Type: multipart/related; type="text/xml"; boundary="'$boundary'"' $2
    $


    It makes use of this small Java code to determine mime type for attachment:

    $ cat MimeType.java 
    import java.net.FileNameMap;
    import java.net.URLConnection;
     
    public class MimeType {
      public static void main(String args[]) throws Exception {
    
        String mimetype = URLConnection.getFileNameMap().getContentTypeFor(args[0]);
     
        System.out.println( (mimetype!=null) ? mimetype : "application/octet-stream" );
      }
    }
    $



    ------------------------------
    Hermann Stamm-Wilbrandt
    Compiler Level 3 support & Fixpack team lead
    IBM DataPower Gateways (⬚ᵈᵃᵗᵃ / ⣏⠆⡮⡆⢹⠁⡮⡆⡯⠂⢎⠆⡧⡇⣟⡃⡿⡃)
    https://stamm-wilbrandt.de/en/blog/
    ------------------------------