Why does a curl POST request crash my Catalyst::Controller::REST controller?-Collection of common programming errors

I’m using Catalyst to build a RESTful web service, so I create a Catalyst controller in the usual way

script/myapp_create.pl controller MyApp::Controller

I then fire up the catalyst test server

script/zoo_server.pl -rd

So far so good – I can now go to http://localhost:3000/user and see the message “Matched MyApp::Controller::User in User.”

I then replace the first BEGIN line in lib/MyApp/Controller/User.pm with the following line

BEGIN { extends 'Catalyst::Controller::REST' }

Before doing anything else, I want to check my ability to execute a POST request and watch the response. So in another terminal window, I type

curl http://localhost:3000/user --verbose --data "whatever" -H "Content-Type: text/xml"

At this point, since I have not implemented any POST methods, I am expecting to see a “405 Method Not Allowed” response. Instead, what I see from curl is this:

* About to connect() to localhost port 3000 (#0)
*   Trying 127.0.0.1... connected
* Connected to localhost (127.0.0.1) port 3000 (#0)
> POST /user HTTP/1.1
> User-Agent: curl/7.19.6 (i386-apple-darwin10.0.0) libcurl/7.19.6 zlib/1.2.5
> Host: localhost:3000
> Accept: */*
> Content-Type: text/xml
> Content-Length: 28
> 
* Empty reply from server
* Connection #0 to host localhost left intact
curl: (52) Empty reply from server
* Closing connection #0

This then appears to crash catalyst’s test server. The server does not log anything, but future attempts to contact the server, e.g. doing another GET request to “localhost:3000/user”, results in “couldn’t connect to host” errors from curl.

I note that this only happens if I use Catalyst::Controller::REST. If I just make a regular controller, POSTing to it does not crash anything. So I’m assuming it happens on the deserialization action, which will be delegated to XML::Simple (as per the default for Catalyst::Controller::REST). Any ideas?

What I eventually want to do, by the way, is create a method like sub thing :Local :ActionClass('REST') ..., and a corresponding sub thing_POST. My understanding is that POST requests to /user/thing containing XML should then automatically get deserialized and put it into $c->request->data, before thing_POST is called. The above tests are a preliminary to this – designed to check what happens if no POST method is defined. (For what it’s worth, I get exactly the same behavior if I create sub thing and sub thing_POST, and then use curl to issue a POST request to /user/thing.)

  1. I eventually traced this to XML::SAX. Reproducible bug condition:

    % cat >! test
    blah
    % perl -e 'use XML::SAX;my $sp = XML::SAX::ParserFactory->parser;my $tree = $sp->parse_uri("test")'
    Segmentation fault
    

    Note that it works fine if the XML is quoted, rather than in a file:

    % perl -e 'use XML::SAX;my $sp = XML::SAX::ParserFactory->parser;my $tree = $sp->parse_string("test");print $tree'
    HASH(0x1009c4470)
    

    Something wrong with my XML::SAX installation, I guess.

  2. You’ve defined your action thing with :Local attribute attached, which means the path which is dispatched is /user/thing (instead of that, you are posting your data to /user). May be you would like to check the Catalyst Manual – Action Types introduction

    Alternatively, if you still experience some problems you could try asking at the official #catalyst irc channel.