Falcon: No way to get POST data if json is posted as application/x-www-form-urlencoded

Created on 6 Mar 2019  路  2Comments  路  Source: falconry/falcon

Posting a json data with "Content-Type: application/x-www-form-urlencoded" header and can't get data from req. Tried req.params, req.media and req.stream.read() - all empty.

auto_parse_form_urlencoded is set to True.

cURL request:
curl 'http://127.0.0.1:8000/' -H 'Accept: application/json, text/plain, */*' --compressed -H 'Content-Type: application/x-www-form-urlencoded' --data '{ "param1": 1 , "param2": "2" }'

I know that it is unusual situation, but that is how a third party app currently works and I'm trying to write a middleware that will convert data to json (already did one for multipart/form-data).

question

Most helpful comment

Hi @mastizada !
Yes, it is very unusual to masquerade JSON as application/x-www-form-urlencoded indeed, but knowing it is a third party app, and not your choice, I will refrain from judgement.

The answer is that it should just work out of the box, unless I misunderstood anything.

Just set auto_parse_form_urlencoded to False instead (False should already be default in recent Falcon versions, but it does not hurt to be explicit):

import json

import falcon


class Responder:

    def on_post(self, req, resp):
        data = req.bounded_stream.read()
        resp.media = json.loads(data.decode())    


api = falcon.API()
api.req_options.auto_parse_form_urlencoded = False
api.add_route('/', Responder())

Then, running this with gunicorn, I could perform your cURL:

curl 'http://127.0.0.1:8000/' -H 'Accept: application/json, text/plain, */*' --compressed -H 'Content-Type: application/x-www-form-urlencoded' --data '{ "param1": 1 , "param2": "2" }'
{"param1": 1, "param2": "2"}

(Setting it to True would have parsed the form as URL-encoded automatically, silencing the errors etc, exactly as you have observed)

What is more, you actually do not even need to use any middleware.
Even though it would look odd, you could also install JSON media handler to handle application/x-www-form-urlencoded, then you could just access your payload as req.media:

import json

import falcon
import falcon.media


class Responder:

    def on_post(self, req, resp):
        resp.media = req.media


api = falcon.API()
api.req_options.auto_parse_form_urlencoded = False
api.req_options.media_handlers = falcon.media.Handlers({
    'application/x-www-form-urlencoded': falcon.media.JSONHandler(),
})

api.add_route('/', Responder())

Hope this helps, but do not hesitate to ask should you still have any issue with the above!

All 2 comments

Hi @mastizada !
Yes, it is very unusual to masquerade JSON as application/x-www-form-urlencoded indeed, but knowing it is a third party app, and not your choice, I will refrain from judgement.

The answer is that it should just work out of the box, unless I misunderstood anything.

Just set auto_parse_form_urlencoded to False instead (False should already be default in recent Falcon versions, but it does not hurt to be explicit):

import json

import falcon


class Responder:

    def on_post(self, req, resp):
        data = req.bounded_stream.read()
        resp.media = json.loads(data.decode())    


api = falcon.API()
api.req_options.auto_parse_form_urlencoded = False
api.add_route('/', Responder())

Then, running this with gunicorn, I could perform your cURL:

curl 'http://127.0.0.1:8000/' -H 'Accept: application/json, text/plain, */*' --compressed -H 'Content-Type: application/x-www-form-urlencoded' --data '{ "param1": 1 , "param2": "2" }'
{"param1": 1, "param2": "2"}

(Setting it to True would have parsed the form as URL-encoded automatically, silencing the errors etc, exactly as you have observed)

What is more, you actually do not even need to use any middleware.
Even though it would look odd, you could also install JSON media handler to handle application/x-www-form-urlencoded, then you could just access your payload as req.media:

import json

import falcon
import falcon.media


class Responder:

    def on_post(self, req, resp):
        resp.media = req.media


api = falcon.API()
api.req_options.auto_parse_form_urlencoded = False
api.req_options.media_handlers = falcon.media.Handlers({
    'application/x-www-form-urlencoded': falcon.media.JSONHandler(),
})

api.add_route('/', Responder())

Hope this helps, but do not hesitate to ask should you still have any issue with the above!

Thanks @vytas7 it works.

Was this page helpful?
0 / 5 - 0 ratings

Related issues

bachrc picture bachrc  路  3Comments

neilalbrock picture neilalbrock  路  5Comments

kgriffs picture kgriffs  路  7Comments

yosiyuki picture yosiyuki  路  8Comments

carlodri picture carlodri  路  5Comments