cancel
Showing results for 
Search instead for 
Did you mean: 

Using cookies with HTTP plain adapter

Former Member
0 Kudos

Hi PI Experts,

I have a 2-step scenario as follow:
- Call an HTTPS service with user-id and password. A cookie is returned by means of "set-cookie" in HTTP header
- Call another HTTPS service, by providing cookie information previously received

I need to send plain http content in the payload (for example, name1=value1;name2=value2).

I encounter problems with cookie management...

My first thought was to use Axis. But that's not possible since we do not have option to send plain http content - Only soap is supported...

So I use Plain HTTP Adapter, with an RFC destination defined in SM59. The "Accept Cookies" field is set to "Yes (All)".

In my scenario, I'm able to do the first call, pass credentials and retrieve cookie through dynamic configuration. I'm not able to provide the cookie during the second call...

I did a test. I renamed the "Cookie" name by "MyCookie", and the value is then transmitted in HTTP Header !!!! This means that everything works from a mapping/configuration perspective.

I'm pretty sure I'm not the only guy trying to use cookies with HTTP Plain Adapter...

How do you guys proceed in such a case ?

Thanks in advance for your valuable help !!

Accepted Solutions (1)

Accepted Solutions (1)

Former Member
0 Kudos

It seems that cookies are NOT managed by the Plain HTTP Outbound adapter, at least in PI 7.11. This adapter is ABAP based in this version of PI, whereas it is Java based in PI 7.3. I hope it will be managed correctly...

Since upgrading is a little bit overkill for what I need, here is the solution I applied. It's working fine.

Adapter is implemented in class CL_HTTP_PLAIN_OUTBOUND. I did 2 enhancements in this class:

- At beginning of method HTTP_ANSWER, I retrieve cookie values using client->response->get_cookies( changing cookies = lt_cookie ) and I store results in database.

- At beginning of method HTTP_POST, I retrieve cookie values from database and pass it to my request using client->request->if_http_entity~set_cookie.

Since I do not want to apply this logic everytime, I use dynamic configuration to keep a "CookieStoreID" which serves as a key for my database table. Dynamic configuration can easily be accessed in both methods by using dy->if_xms_msghdr30_dynamic~get_record.

former_member181985
Active Contributor
0 Kudos

It is good that you only found the solution. The solution you have provided is on a high level . Can  you please share your  solution as a blog/document on SDN which will help fellow SDNers.

Thanks,

Praveen Gujjeti

Answers (2)

Answers (2)

iaki_vila
Active Contributor
0 Kudos

Hi Anne,

As Mike says you can use a java mapping to work with this. In my case i found the next code on internet to work with cookies and it was easy to work with this:

import java.net.*;

import java.io.*;

import java.util.*;

import java.text.*;

public class CookieManager {

    private Map store;

    private static final String SET_COOKIE = "Set-Cookie";

    private static final String COOKIE_VALUE_DELIMITER = ";";

    private static final String PATH = "path";

    private static final String EXPIRES = "expires";

    private static final String DATE_FORMAT = "EEE, dd-MMM-yyyy hh:mm:ss z";

    private static final String SET_COOKIE_SEPARATOR="; ";

    private static final String COOKIE = "Cookie";

    private static final char NAME_VALUE_SEPARATOR = '=';

    private static final char DOT = '.';

    private DateFormat dateFormat;

    public CookieManager() {

        store = new HashMap();

        dateFormat = new SimpleDateFormat(DATE_FORMAT);

    }

    /**

     * Retrieves and stores cookies returned by the host on the other side

     * of the the open java.net.URLConnection.

     *

     * The connection MUST have been opened using the connect()

     * method or a IOException will be thrown.

     *

     * @param conn a java.net.URLConnection - must be open, or IOException will be thrown

     * @throws java.io.IOException Thrown if conn is not open.

     */

    public void storeCookies(URLConnection conn) throws IOException {

        // let's determine the domain from where these cookies are being sent

        String domain = getDomainFromHost(conn.getURL().getHost());

        Map domainStore; // this is where we will store cookies for this domain

        // now let's check the store to see if we have an entry for this domain

        if (store.containsKey(domain)) {

            // we do, so lets retrieve it from the store

            domainStore = (Map)store.get(domain);

        } else {

            // we don't, so let's create it and put it in the store

            domainStore = new HashMap();

            store.put(domain, domainStore);

        }

        // OK, now we are ready to get the cookies out of the URLConnection

        String headerName=null;

        for (int i=1; (headerName = conn.getHeaderFieldKey(i)) != null; i++) {

            if (headerName.equalsIgnoreCase(SET_COOKIE)) {

                Map cookie = new HashMap();

                StringTokenizer st = new StringTokenizer(conn.getHeaderField(i), COOKIE_VALUE_DELIMITER);

                // the specification dictates that the first name/value pair

                // in the string is the cookie name and value, so let's handle

                // them as a special case:

                if (st.hasMoreTokens()) {

                    String token  = st.nextToken();

                    String name = token.substring(0, token.indexOf(NAME_VALUE_SEPARATOR));

                    String value = token.substring(token.indexOf(NAME_VALUE_SEPARATOR) + 1, token.length());

                    domainStore.put(name, cookie);

                    cookie.put(name, value);

                }

                while (st.hasMoreTokens()) {

                    String token  = st.nextToken();

                    cookie.put(token.substring(0, token.indexOf(NAME_VALUE_SEPARATOR)).toLowerCase(),

                     token.substring(token.indexOf(NAME_VALUE_SEPARATOR) + 1, token.length()));

                }

            }

        }

    }

    /**

     * Prior to opening a URLConnection, calling this method will set all

     * unexpired cookies that match the path or subpaths for thi underlying URL

     *

     * The connection MUST NOT have been opened

     * method or an IOException will be thrown.

     *

     * @param conn a java.net.URLConnection - must NOT be open, or IOException will be thrown

     * @throws java.io.IOException Thrown if conn has already been opened.

     */

    public void setCookies(URLConnection conn) throws IOException {

        // let's determine the domain and path to retrieve the appropriate cookies

        URL url = conn.getURL();

        String domain = getDomainFromHost(url.getHost());

        String path = url.getPath();

        Map domainStore = (Map)store.get(domain);

        if (domainStore == null) return;

        StringBuffer cookieStringBuffer = new StringBuffer();

        Iterator cookieNames = domainStore.keySet().iterator();

        while(cookieNames.hasNext()) {

            String cookieName = (String)cookieNames.next();

            Map cookie = (Map)domainStore.get(cookieName);

            // check cookie to ensure path matches  and cookie is not expired

            // if all is cool, add cookie to header string

            if (comparePaths((String)cookie.get(PATH), path) && isNotExpired((String)cookie.get(EXPIRES))) {

                cookieStringBuffer.append(cookieName);

                cookieStringBuffer.append("=");

                cookieStringBuffer.append((String)cookie.get(cookieName));

                if (cookieNames.hasNext()) cookieStringBuffer.append(SET_COOKIE_SEPARATOR);

            }

        }

        try {

            conn.setRequestProperty(COOKIE, cookieStringBuffer.toString());

        } catch (java.lang.IllegalStateException ise) {

            IOException ioe = new IOException("Illegal State! Cookies cannot be set on a URLConnection that is already connected. "

            + "Only call setCookies(java.net.URLConnection) AFTER calling java.net.URLConnection.connect().");

            throw ioe;

        }

    }

    private String getDomainFromHost(String host) {

        if (host.indexOf(DOT) != host.lastIndexOf(DOT)) {

            return host.substring(host.indexOf(DOT) + 1);

        } else {

            return host;

        }

    }

    private boolean isNotExpired(String cookieExpires) {

        if (cookieExpires == null) return true;

        Date now = new Date();

        try {

            return (now.compareTo(dateFormat.parse(cookieExpires))) <= 0;

        } catch (java.text.ParseException pe) {

            pe.printStackTrace();

            return false;

        }

    }

    private boolean comparePaths(String cookiePath, String targetPath) {

        if (cookiePath == null) {

            return true;

        } else if (cookiePath.equals("/")) {

            return true;

        } else if (targetPath.regionMatches(0, cookiePath, 0, cookiePath.length())) {

            return true;

        } else {

            return false;

        }

    }

    /**

     * Returns a string representation of stored cookies organized by domain.

     */

    public String toString() {

        return store.toString();

    }

    public static void main(String[] args) {

        CookieManager cm = new CookieManager();

        try {

            URL url = new URL("http://www.hccp.org/test/cookieTest.jsp");

            URLConnection conn = url.openConnection();

            conn.connect();

            cm.storeCookies(conn);

            System.out.println(cm);

            cm.setCookies(url.openConnection());

        } catch (IOException ioe) {

            ioe.printStackTrace();

        }

    }

}

Later, in the main class i instanced an CookieManager object:

cookie = new CookieManager();

During the process  i store the cookie:

private URLConnection openConnection() throws Exception {

   //Open the connection to get the cookies
  
   URL myUrl = new URL(this.cons.urlCookie);

   URLConnection urlConn = myUrl.openConnection();

   urlConn.connect();

   //Store the cookies in memory
  
   cookie.storeCookies(urlConn);
   return urlConn;

    }

Finally i use the stored cookie for a second connection:

    //Accept all certificates
   trustAllHttpsCertificates();
   URL miUrls = new URL(url);

   //
  
   URLConnection urlConn = miUrls.openConnection();

   HttpURLConnection httpConn = (HttpURLConnection) urlConn;
   // Se elimina la redirección que se produce nada más realizar la conexión

   httpConn.setInstanceFollowRedirects(false);

   //Use the cookies previously stored (to autenticate)
   cookie.setCookies(urlConn);

   urlConn.connect();

Regards

Former Member
0 Kudos

Thanks Iñaki. However this solution is to rewrite completely the Plain HTTP Adapter, which I do not want.

I'm looking for the standard way in SAP PI to deal with cookies. I can not believe that there is no standard solution to this standard requirement !!!

Any other idea ?

markangelo_dihiansan
Active Contributor
0 Kudos

Hello,

Since you are already able to retrieve the cookies in the first call via dynamic configuration, why not make the second call using a UDF e.g create an HTTPs Call using Java?

Hope this helps,

Mark