Search code examples
erlangejabberd

Why is Ejabberd handling PUT and POST requests differently?


This seems to cause strange behaviour when PUT has a body larger than a certain length (in my case it is 902 bytes), i.e. ejabberd trims the body (in my case it receives malformed JSON).

Github reference: https://github.com/processone/ejabberd/blob/master/src/ejabberd_http.erl#L403

If I change the case statement to:

        case Method of
        _AnyMethod ->
            case recv_data(State) of
            {ok, Data} ->
                LQuery = case catch parse_urlencoded(Data) of
                     {'EXIT', _Reason} -> [];
                     LQ -> LQ
                     end,
                {State, {LPath, LQuery, Data}};
            error ->
                {State, false}
            end
        end

then the body is parsed correctly.

Is this a configuration issue? How can I force Ejabberd to correctly parse the JSON body?


Solution

  • Looks like you've found a bug.

    As you've noticed, for POST requests the function recv_data is called, which checks the Content-Length header and reads that many bytes from the socket. For PUT requests however, it only uses Trail, which is the data that has been already received while reading HTTP request headers. (This happens in the receive_headers function, which sends a length of 0 to the recv function, meaning that it won't wait for any specific amount of data.)

    How much of the request body is received is going to depend on the size of the headers, as well as the way the client sends the request. If for example the client first sends the headers in one network packet, and then the request body in the next network packet, ejabberd wouldn't pick up the request body at all.