Loading ...
Sorry, an error occurred while loading the content.

Using SOAP::Transport::IO::Server to process request

Expand Messages
  • iancrogers
    Hello. I m new to the list today, so be kind to me. :) I ve searched docs, Pavel s O Reilly book, and now this list for a clue, but I m still at a loss, so
    Message 1 of 5 , Jan 27, 2002
    • 0 Attachment
      Hello. I'm new to the list today, so be kind to me. :) I've
      searched docs, Pavel's O'Reilly book, and now this list for a clue,
      but I'm still at a loss, so I'll post here and hope for the best.

      I'm trying to write a simple HTTP server that serves specific files,
      OR processes a SOAP request. I listen on a socket and parse the
      header of an incoming request. If the request is the SOAP POST, I
      try to process with SOAP::Transport::IO::Server. Here's where my
      code is, currently:

      (important excerpts here, let me know if you want more)
      ------------
      while ( $client_address = accept( CLIENT, SERVER) ) {

      ...

      # Read HTTP header info
      LINE: while ( $buf = <CLIENT> ) {
      chomp( $buf );
      last LINE if ( length( $buf ) == 1 );
      $some_data .= "$buf\n";
      }

      ...

      if ( $some_data =~ /^POST \/SOAPONAROPE HTTP/ ) {
      print CLIENT "HTTP/1.1 200 OK\n";
      print CLIENT "Content-Type: text/xml\n\n";

      SOAP::Transport::IO::Server
      -> new( )
      -> in ( CLIENT )
      -> out( CLIENT )
      -> dispatch_to( 'MuseClient' )
      -> handle
      ;
      }

      package MuseClient;
      sub test_routine {
      my ( $self, $email, $password, $XML ) = @_;
      return "BLING\n";
      }
      ------

      And the client:
      ---------------
      $soap_uri = "http://localhost/MuseClient";
      $soap_proxy = "http://localhost/SOAPONAROPE";
      print SOAP::Lite # fix tags
      -> uri($soap_uri)
      -> proxy($soap_proxy)
      -> test_routine( $email, $password, $XML )
      -> result . "\n";
      ---------------

      which returns: 500 Connection reset by peer

      if I change -> out( CLIENT ) to -> out( 'TESTING.xml' ), TESTING.xml
      gets the following:

      <?xml version="1.0" encoding="UTF-8"?><SOAP-ENV:Envelope xmlns:SOAP-
      ENC="http://schema
      s.xmlsoap.org/soap/encoding/" SOAP-
      ENV:encodingStyle="http://schemas.xmlsoap.org/soap/
      encoding/" xmlns:SOAP-
      ENV="http://schemas.xmlsoap.org/soap/envelope/" xmlns:xsi="http:
      //www.w3.org/1999/XMLSchema-instance"
      xmlns:xsd="http://www.w3.org/1999/XMLSchema"><SO
      AP-ENV:Body><SOAP-ENV:Fault><faultcode xsi:type="xsd:string">SOAP-
      ENV:Client</faultcod
      e><faultstring xsi:type="xsd:string">Failed to access class
      (soap::envelope): Can't lo
      cate soap/envelope.pm in @INC (@INC contains:) at (eval 91) line 3,
      <GEN0> line 3.
      </faultstring></SOAP-ENV:Fault></SOAP-ENV:Body></SOAP-ENV:Envelope>

      However, if I then change -> in ( CLIENT ) to -> in ( 'INPUT.xml' ),
      and load INPUT.xml like so (prior to the 'if' in the above code
      block):

      open ( SO, "> INPUT.xml" );
      $msg_body = "";
      LINE: while ( recv( CLIENT, $buf, 1, 0 ) ) {
      print SO $buf;
      print $buf;
      $msg_body .= $buf;
      last LINE if ( $msg_body =~ /<\/SOAP-ENV:Envelope>/ );
      }
      close SO;

      I get what I would expect in TESTING.xml:

      <?xml version="1.0" encoding="UTF-8"?><SOAP-ENV:Envelope xmlns:SOAP-
      ENC="http://schema
      s.xmlsoap.org/soap/encoding/" SOAP-
      ENV:encodingStyle="http://schemas.xmlsoap.org/soap/
      encoding/" xmlns:SOAP-
      ENV="http://schemas.xmlsoap.org/soap/envelope/" xmlns:xsi="http:
      //www.w3.org/1999/XMLSchema-instance"
      xmlns:xsd="http://www.w3.org/1999/XMLSchema"><SO
      AP-ENV:Body><namesp1:test_routineResponse
      xmlns:namesp1="http://localhost/MuseClient">
      <s-gensym3 xsi:type="xsd:string">BLING
      </s-gensym3></namesp1:test_routineResponse></SOAP-ENV:Body></SOAP-
      ENV:Envelope>

      I feel very close.

      I guess my first question is, is this how you would write a very
      simple server that handles a small handful of very specific requests?

      Then, I'm wondering what I'm doing wrong in my use of the
      SOAP::Transport::IO::Server that prevents me from getting the
      desired result.

      Any clues or assistance are appreciated.

      ian
    • iancrogers
      I ve sorted this out, somewhat. SOAP::Transport::IO::Server - new( ) - in ( CLIENT ) - out( CLIENT ) - dispatch_to( MuseClient ) - handle ; writes
      Message 2 of 5 , Jan 29, 2002
      • 0 Attachment
        I've sorted this out, somewhat.

        SOAP::Transport::IO::Server
        -> new( )
        -> in ( CLIENT )
        -> out( CLIENT )
        -> dispatch_to( 'MuseClient' )
        -> handle
        ;

        writes output to a file 'CLIENT'.

        The following gives the desired result by first writing the request
        to a file:

        open ( SO, "> INPUT.xml" );
        $msg_body = "";
        LINE: while ( recv( CLIENT, $buf, 1, 0 ) ) {
        print SO $buf;
        $msg_body .= $buf;
        last LINE if ( $msg_body =~ /<\/SOAP-ENV:Envelope>/ );
        }
        close SO;

        print CLIENT "HTTP/1.1 200 OK\n";
        print CLIENT "Content-Type: text/xml\n\n";

        SOAP::Transport::IO::Server
        -> new( )
        -> in ( 'INPUT.xml' )
        -> out( *CLIENT )
        -> dispatch_to( 'MuseClient' )
        -> handle
        ;

        This, however, blocks forever:

        SOAP::Transport::IO::Server
        -> new( )
        -> in ( *CLIENT )
        -> out( *CLIENT )
        -> dispatch_to( 'MuseClient' )
        -> handle
        ;

        Client is making the SOAP request as in the previous post:

        print SOAP::Lite
        -> uri($soap_uri)
        -> proxy($soap_proxy)
        -> test_routine( $email, $password, $XML )
        -> result . "\n";

        I assume this is a buffering issue. The client doesn't send a
        newline at the end of the request, and the read waits forever for
        this last record separator. This is why while( <CLIENT> ) wasn't
        working for me, I think, and I had to resort to reading one
        character at a time.

        Obviously, I don't want to have to write the SOAP request to a file
        before I process it. Can someone suggest an alternative?

        Thanks in advance,
        ian
      • Paul Kulchenko
        Hi, Ian! ... It depends on what do you want to do ;). ... This won t work. You can t easily read from and write to the same filehandle. From IPC::Open2: This
        Message 3 of 5 , Jan 29, 2002
        • 0 Attachment
          Hi, Ian!

          > Obviously, I don't want to have to write the SOAP request to a file
          > before I process it. Can someone suggest an alternative?
          It depends on what do you want to do ;).

          > -> in ( *CLIENT )
          > -> out( *CLIENT )
          This won't work. You can't easily read from and write to the same
          filehandle. From IPC::Open2:

          This whole affair is quite dangerous, as you may block forever. It
          assumes it's going to talk to something like B<bc>, both writing
          to it and reading from it. This is presumably safe because you
          "know" that commands like B<bc> will read a line at a time and
          output a line at a time. Programs like B<sort> that read their
          entire input stream first, however, are quite apt to cause deadlock.

          If you have file or stream you can use SOAP::Transport::IO to handle
          that. If you have HTTP, you can use SOAP::Transport::HTTP::* module
          to handle that. If you use combination of those and want to handle
          transport level yourself, you can use SOAP::Server to handle payload:

          $response_xml = SOAP::Server
          ->dispatch_to(...)
          ->handle($request_xml);

          In this case you don't need to create a file and then process it with
          ::IO transport. Hope it helps. Please provide little bit more details
          if you still have problems.

          Best wishes, Paul.

          --- iancrogers <ian@...> wrote:
          > I've sorted this out, somewhat.
          >
          > SOAP::Transport::IO::Server
          > -> new( )
          > -> in ( CLIENT )
          > -> out( CLIENT )
          > -> dispatch_to( 'MuseClient' )
          > -> handle
          > ;
          >
          > writes output to a file 'CLIENT'.
          >
          > The following gives the desired result by first writing the request
          >
          > to a file:
          >
          > open ( SO, "> INPUT.xml" );
          > $msg_body = "";
          > LINE: while ( recv( CLIENT, $buf, 1, 0 ) ) {
          > print SO $buf;
          > $msg_body .= $buf;
          > last LINE if ( $msg_body =~ /</SOAP-ENV:Envelope>/ );
          > }
          > close SO;
          >
          > print CLIENT "HTTP/1.1 200 OK
          ";
          > print CLIENT "Content-Type: text/xml

          ";
          >
          > SOAP::Transport::IO::Server
          > -> new( )
          > -> in ( 'INPUT.xml' )
          > -> out( *CLIENT )
          > -> dispatch_to( 'MuseClient' )
          > -> handle
          > ;
          >
          > This, however, blocks forever:
          >
          > SOAP::Transport::IO::Server
          > -> new( )
          > -> in ( *CLIENT )
          > -> out( *CLIENT )
          > -> dispatch_to( 'MuseClient' )
          > -> handle
          > ;
          >
          > Client is making the SOAP request as in the previous post:
          >
          > print SOAP::Lite
          > -> uri($soap_uri)
          > -> proxy($soap_proxy)
          > -> test_routine( $email, $password, $XML )
          > -> result . "
          ";
          >
          > I assume this is a buffering issue. The client doesn't send a
          > newline at the end of the request, and the read waits forever for
          > this last record separator. This is why while( <CLIENT> ) wasn't
          > working for me, I think, and I had to resort to reading one
          > character at a time.
          >
          > Obviously, I don't want to have to write the SOAP request to a file
          >
          > before I process it. Can someone suggest an alternative?
          >
          > Thanks in advance,
          > ian
          >
          >
          > ------------------------ Yahoo! Groups Sponsor
          >
          > To unsubscribe from this group, send an email to:
          > soaplite-unsubscribe@yahoogroups.com
          >
          >
          >
          > Your use of Yahoo! Groups is subject to
          > http://docs.yahoo.com/info/terms/
          >
          >


          __________________________________________________
          Do You Yahoo!?
          Great stuff seeking new owners in Yahoo! Auctions!
          http://auctions.yahoo.com
        • ian c rogers
          ... SOAP::Server got me much further, but I m still having sporadic results. Let me explain in a bit more detail what I m trying to do, as I feel I might be
          Message 4 of 5 , Feb 1, 2002
          • 0 Attachment
            > If you have file or stream you can use SOAP::Transport::IO to handle
            > that. If you have HTTP, you can use SOAP::Transport::HTTP::* module
            > to handle that. If you use combination of those and want to handle
            > transport level yourself, you can use SOAP::Server to handle payload:

            SOAP::Server got me much further, but I'm still having sporadic results.

            Let me explain in a bit more detail what I'm trying to do, as I feel I might
            be approaching this the wrong way. I have a simple program that has a
            simple (forking) HTTP server within it. The HTTP server may be called upon
            to serve a few specific files, or it may receive a SOAP request. I handle
            either by reading in the HTTP header like so:

            # Read HTTP header info
            LINE: while ( $buf = <CLIENT> ) {
            chomp( $buf );
            last LINE if ( length( $buf ) == 1 );
            $some_data .= "$buf\n";
            }

            and then serve the file if I see /^GET (\/.+txt) HTTP/ or handle the SOAP
            if I see /^POST \/SOAPONAROPE HTTP/. Here's how I'm handling the SOAP now:

            $request_xml = "";
            LINE: while ( recv( CLIENT, $buf, 1, 0 ) ) {
            $request_xml .= $buf;
            last LINE if ( $request_xml =~ /<\/SOAP-ENV:Envelope>/ ||
            $request_xml eq "" );
            }
            $response_xml = SOAP::Server
            ->dispatch_to( 'TestPackage' )
            ->handle($request_xml);

            print CLIENT "HTTP/1.1 200 OK\n";
            print CLIENT "Content-Type: text/xml\n\n";
            print CLIENT "$response_xml\n";

            is simply:

            package TestPackage;

            sub test_routine {
            my ( $self, $email, $password, $XML ) = @_;

            return "AW YEAH!\n";
            }

            And the soap_client.pl is:

            $soap_uri = "http://localhost/TestPackage";
            $soap_proxy = "http://localhost/SOAPONAROPE";
            print "calling test_routine via $soap_proxy: ";
            print SOAP::Lite # fix tags
            -> uri($soap_uri)
            -> proxy($soap_proxy)
            -> test_routine( $email, $password, $XML )
            -> result . "\n";
            exit;

            Sample output:

            $ ./soap_client.pl
            calling test_routine via http://localhost/SOAPONAROPE: AW YEAH!

            $ ./soap_client.pl
            calling test_routine via http://localhost/SOAPONAROPE: AW YEAH!

            $ ./soap_client.pl
            calling test_routine via http://localhost/SOAPONAROPE: AW YEAH!

            $ ./soap_client.pl
            calling test_routine via http://localhost/SOAPONAROPE: AW YEAH!

            $ ./soap_client.pl
            calling test_routine via http://localhost/SOAPONAROPE: 500 read timeout
            at ./soap_client.pl line 30
            $ ./soap_client.pl
            calling test_routine via http://localhost/SOAPONAROPE: AW YEAH!

            $ ./soap_client.pl
            calling test_routine via http://localhost/SOAPONAROPE: AW YEAH!

            On the timeout run, the header info is read, but the server blocks forever
            on the recv() at LINE. I've added some code to take a look at the socket to
            see if there's any data to be read there, and as you might guess, sometimes
            there isn't (which avoids the timeout but not the larger problem). Why not?

            Clearly I'm no whiz at handling the transport myself and I'd prefer not to.
            Is there another way in my case? If not, suggestions? Any idea why my
            soap_client.pl would be sending header only then blocking sometimes? What
            other factors might be to blame?

            Thanks again for your help. Sorry for the delay in follow-up, I had minor
            surgery Weds am. :)

            ian
          • Duncan Cameron
            ... Presumably this works, but what is the above line actually testing? ... ... I suggest using HTTP::Daemon to construct your server. That should
            Message 5 of 5 , Feb 2, 2002
            • 0 Attachment
              On 2002-02-01 ian c rogers <ian@...> wrote:

              >Let me explain in a bit more detail what I'm trying to do, as I feel I might
              >be approaching this the wrong way. I have a simple program that has a
              >simple (forking) HTTP server within it. The HTTP server may be called upon
              >to serve a few specific files, or it may receive a SOAP request. I handle
              >either by reading in the HTTP header like so:
              >
              > # Read HTTP header info
              > LINE: while ( $buf = <CLIENT> ) {
              > chomp( $buf );
              > last LINE if ( length( $buf ) == 1 );

              Presumably this works, but what is the above line actually testing?

              > $some_data .= "$buf\n";
              > }
              >
              <snipped>

              >On the timeout run, the header info is read, but the server blocks forever
              >on the recv() at LINE. I've added some code to take a look at the socket to
              >see if there's any data to be read there, and as you might guess, sometimes
              >there isn't (which avoids the timeout but not the larger problem). Why not?
              >
              >Clearly I'm no whiz at handling the transport myself and I'd prefer not to.
              >Is there another way in my case? If not, suggestions? Any idea why my
              >soap_client.pl would be sending header only then blocking sometimes? What
              >other factors might be to blame?

              I suggest using HTTP::Daemon to construct your server. That should
              avoid many of the possible problems which you might be hitting.

              Also, I'm no expert in sockets but is it a good idea to mix stdio type
              input (using <CLIENT>) and recv() input on the same socket?
              There should be a Content-length header which tells you _exactly_ how
              many bytes to read so you don't have to read one byte at a time.

              Regards

              Duncan Cameron
            Your message has been successfully submitted and would be delivered to recipients shortly.