4 Replies Latest reply on Jan 22, 2008 3:02 PM by andrew.morrison

    Proxy sends AMF rather than SOAP

    andrew.morrison
      I am attempting to set up SOAP communication over SSL between an AIR application and a remote server using Basic HTTP authentication. I've gathered that this is only possible to do via the WebService proxy. I have been unable, however, to convince the proxy to speak SOAP rather than AMF. The documentation on services-config.xml settings have been a bit light, and so its difficult to tell how the problem can be fixed. I've compiled the code with Flex 3 Beta 3 as well as Flex 3.0.0 with the same results.

      After instantiating a WebService and configuring it to use the proxy (useProxy=true), loadWSDL() causes an AMF message to be sent to the SOAP server as some kind of a ping. The SOAP server, of course, can't parse this and returns a SOAP fault. The WebService, expecting AMF in response pukes and throws an error, without having loaded the WSDL.

      Below is the code used to load the WSDL.

      var ws:WebService =
      new WebService('destination.cpiapi.https',
      'https://192.168.1.123:8080/api/cpiapi.php');
      ws.useProxy = true;
      ws.loadWSDL();

      The following is my services-config.xml. I'm guessing that there is a misconfiguration somewhere here that is telling the proxy to talk AMF rather than SOAP. Note that there are crossing references to HTTP and HTTPS throughout this posting ... using SSL hasn't been a problem, so I switched to HTTP so I could sniff the messages without having changed my nomenclature. Ignore that.


      <?xml version="1.0" encoding="UTF-8"?>
      <services-config>
      <services>
      <service id="service.cpiapi"
      class="flex.messaging.services.http.SOAPProxyAdapter"
      messageTypes="flex.messaging.messages.HTTPMessage,flex.messaging.messages.SOAPMessage">
      <destination id="destination.cpiapi.https">
      <channels>
      <channel ref="channel.https"/>
      </channels>
      <properties>
      <wsdl> http://192.168.1.123:8080/cpiapi.wsdl</wsdl>
      <soap> http://1921.68.1.123:8080/api/cpiapi.php</soap>
      </properties>
      <security>
      <security-constraint ref="security.authBasic" />
      </security>
      </destination>
      </service>
      </services>
      <channels>
      <channel-definition id="channel.https"
      class="mx.messaging.channels.HTTPChannel">
      <endpoint
      uri=" http://192.168.1.123:8080/api/cpiapi.php"
      class="flex.messaging.endpoints.HTTPEndpoint"
      />
      </channel-definition>
      </channels>
      <security>
      <security-constraint id="security.authBasic">
      <auth-method>basic</auth-method>
      </security-constraint>
      </security>
      </services-config>


      After compiling (referencing services-config.xml with the amxmlc flag '-services=services-config.xml') and running the code, the loadWSDL() call causes the following message to be sent to the endpointURI.


      [HTTP Headers Removed]

      <amfx ver="3" xmlns=" http://www.macromedia.com/2005/amfx">
      <body>
      <object type="flex.messaging.messages.CommandMessage">
      <traits>
      <string>body</string>
      <string>clientId</string>
      <string>correlationId</string>
      <string>destination</string>
      <string>headers</string>
      <string>messageId</string>
      <string>operation</string>
      <string>timestamp</string>
      <string>timeToLive</string>
      </traits>
      [ ... ]
      </body></amfx>

      As expected, the server responds with a SOAP encoded Fault, and an exception is thrown when an attempt is made to decode the fault as AMF.


      [MessagingError message='Invalid AMFX packet. Content must start with an <amfx> node']
      at mx.messaging.channels.amfx::AMFXDecoder$/decodePacket()[E:\dev\flex_3_beta3\sdk\framework s\projects\rpc\src\mx\messaging\channels\amfx\AMFXDecoder.as:155]
      at mx.messaging.channels.amfx::AMFXDecoder/decode()[E:\dev\flex_3_beta3\sdk\frameworks\proje cts\rpc\src\mx\messaging\channels\amfx\AMFXDecoder.as:97]
      at mx.messaging.channels::HTTPChannel/decodePacket()[E:\dev\flex_3_beta3\sdk\frameworks\proj ects\rpc\src\mx\messaging\channels\HTTPChannel.as:545]
      at mx.messaging.channels::HTTPChannel/pingCompleteHandler()[E:\dev\flex_3_beta3\sdk\framewor ks\projects\rpc\src\mx\messaging\channels\HTTPChannel.as:557]
      at ChannelRequestLoader/callEventCallback()[E:\dev\flex_3_beta3\sdk\frameworks\projects\rpc\ src\mx\messaging\channels\HTTPChannel.as:1164]
      at ChannelRequestLoader/completeHandler()[E:\dev\flex_3_beta3\sdk\frameworks\projects\rpc\sr c\mx\messaging\channels\HTTPChannel.as:1200]
      at flash.events::EventDispatcher/dispatchEventFunction()
      at flash.events::EventDispatcher/dispatchEvent()
      at flash.net::URLLoader/onComplete()




      So, my question is, why is the proxy talking AMF? When I set useProxy=false, no AMF messages are sent, and SOAP communication goes just fine as long as i never setCredentials(user,pass) on the WebService (whith throws a fault, telling me that I need to useProxy). Is there a config within services-config.xml that will tell HTTPChannel to not send out an AMF ping?
        • 1. Re: Proxy sends AMF rather than SOAP
          Peter Farland Level 3
          This should be irrelevant to your SOAP request. It is merely a messaging framework detail that controls how the Flash Player client talks to the Message Broker on the server. The message broker will forward details on to the Proxy Service and the Proxy Service will then send your SOAP request over raw HTTP.

          Note that AMFX is just an XML format (that is modelled on AMF) for the HTTPChannel to use to talk to the message broker (this text-only protocol exists for the scenarios where restrictive firewalls block various mime types, say, perhaps binary AMF). It does not represent how the proxy is talking to your ultimate soap endpoint.

          So, either the client is incorrectly configured and is somehow not using the proxy to make the connection, or an error really did happen and the AMFX encoded response from the message broker to the Flash Player is somehow invalid and also hiding the real error that happened.

          Can you try to use the AMFChannel instead (yes, perhaps it sounds weird, but again, AMF is just the format that the Flash Player will use to talk to the Proxy Service).
          • 2. Re: Proxy sends AMF rather than SOAP
            Peter Farland Level 3
            Actually, I see the problem. It is a misconfiguration indeed.

            Your channel-definition is incorrect. You need your channel-definition to point the HTTPChannel to your message broker servlet as you must first talk to the message broker so that it will get the proxy to do the work for you.

            <channel-definition id="channel.https"
            class="mx.messaging.channels.HTTPChannel">
            <endpoint
            uri=" http://myblazedsserver:8080/blazedsapp/messagebroker/http"
            class="flex.messaging.endpoints.HTTPEndpoint"
            />
            </channel-definition>
            • 3. Re: Proxy sends AMF rather than SOAP
              andrew.morrison Level 1
              Thanks for the reply. I had incorrectly thought that the proxy was an embedded/transparent entity within the AIR engine. I had set the endpoint URI to be the webservice, not the URI of a some kind of AMF proxy.

              My initial goal was to be able to set HTTP Authentication Headers, as in 'Authentication: Basic ...'. I'd be a bad engineer if I set up a proxy just so that I could use AbstractWebService.set[Remote]Credentials(). My first attempt at not using a proxy was to do:

              var ws:WebService = new WebService();
              ws.useProxy = false;
              ws.wsdl = '...';
              ws.endpointURI = '...';
              var header:URLRequestHeader =
              new URLRequestHeader("Authentication", "Basic ...");
              ws.httpHeaders = header;

              The header was being ignored however. The documentation available to me isn't doing much to tell me if httpHeaders:Object wanted a URLRequestHeader or just a string, or just a name:value pair object ... none of them seem to make a difference. Is the httpHeaders parameter only used in the useProxy=true setting?

              Thanks again for the help. Any more help in pushing me in the right direction toward doing HTTP Authenticated SOAP communication would be greatly appreciated.
              • 4. Proxy sends AMF rather than SOAP
                andrew.morrison Level 1
                The following bug report was helpful:

                http://bugs.adobe.com/jira/browse/SDK-12198

                The workaround suggested is to set the authentication variables within the URL as

                https://USER:PASS@enpoint.com/api/

                The bug report seems to suggest that httpHeader ought to work, however I haven't been able to show this to be the case.