1

I write this little WSGI script :

def application(environ, start_response):
    data = '\n'.join(sorted(['%s = %s' % i for i in environ.items()]))
    print data
    start_response("200 OK", [
        ("Content-Type", "text/plain"),
        ("Content-Length", str(len(data)))
    ])
    return iter([data])

I am wondering how can I detect I receive an ajax request : When I run it with gunicorn and when I generate an ajax request with $.ajax() from jQuery, I got this for environ variable:

HTTP_ACCEPT = */*
HTTP_ACCEPT_ENCODING = gzip, deflate, sdch, br
HTTP_ACCEPT_LANGUAGE = fr-FR,fr;q=0.8,en-US;q=0.6,en;q=0.4
HTTP_ACCESS_CONTROL_REQUEST_HEADERS = 16hhs673uh
HTTP_ACCESS_CONTROL_REQUEST_METHOD = GET
HTTP_CONNECTION = keep-alive
HTTP_HOST = localhost:8222
HTTP_ORIGIN = http://localhost:6543
HTTP_REFERER = http://localhost:6543/test2
HTTP_USER_AGENT = Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/55.0.2883.87 Safari/537.36
PATH_INFO = /test2
QUERY_STRING = name=John4&time=2pm
RAW_URI = /test2?name=John4&time=2pm
REMOTE_ADDR = 127.0.0.1
REMOTE_PORT = 40668
REQUEST_METHOD = OPTIONS
SCRIPT_NAME = 
SERVER_NAME = 127.0.0.1
SERVER_PORT = 8222
SERVER_PROTOCOL = HTTP/1.1
SERVER_SOFTWARE = gunicorn/19.7.1
gunicorn.socket = <socket._socketobject object at 0x7f14844e51a0>
wsgi.errors = <gunicorn.http.wsgi.WSGIErrorsWrapper object at 0x7f14844e47d0>
wsgi.file_wrapper = <class 'gunicorn.http.wsgi.FileWrapper'>
wsgi.input = <gunicorn.http.body.Body object at 0x7f14844e4950>
wsgi.multiprocess = False
wsgi.multithread = False
wsgi.run_once = False
wsgi.url_scheme = http
wsgi.version = (1, 0)

I do not see any information like HTTP_X_REQUESTED_WITH, so how Django or Pyramid can known it is an ajax request ?

Eric
  • 4,821
  • 6
  • 33
  • 60
  • Why do you need to know that on the server side? Why should you care whether the client waits for a response or handles it asynchronous (or what language they use)? – UnholySheep May 18 '17 at 16:12
  • I want to check that for security reasons. – Eric May 18 '17 at 16:21
  • I'm not really sure what security reasons that might be, but AFAIK you cannot tell it (as the client has no obligations to send any such information) - I guess the `HTTP_USER_AGENT` is the closest you can get to knowing that it was sent from a browser – UnholySheep May 18 '17 at 16:23
  • But how Django or Pyramid can detect that ? Pyramid has request.is_ajax for exemple, I use it very frequently but I cannot figure out how they detect that. For performance reason also, I do not want to use these frameworks. – Eric May 18 '17 at 16:33
  • ...Sorry request.is_xhr for pyramid – Eric May 18 '17 at 16:43

1 Answers1

0

I found the problem :

I had 2 servers : one for serving the web page that has the $.ajax() script, and another one to answer the ajax request.

Browsers do not like to have ajax resquest not served on the same domain AND port as the web page that start the request.

In my case, I had the web pages served by pyramid at localhost:6543 and the ajax request served by gunicorn at localhost:8222.

When serving all requests (pages + ajax) on the same server at localhost:6543, no more problem, I got all wanted headers. As a bonus, I even got the headers set in $.ajax() function (that was not the case when using 2 servers).

Here are now the environ variable:

HTTP_ACCEPT = */*
HTTP_ACCEPT_ENCODING = gzip, deflate, sdch, br
HTTP_ACCEPT_LANGUAGE = fr-FR,fr;q=0.8,en-US;q=0.6,en;q=0.4
HTTP_CONNECTION = keep-alive
HTTP_HOST = localhost:6543
HTTP_MY_CUSTOM_AJAX_HEADER = mycustomvalue
HTTP_REFERER = http://localhost:6543/SomePath
HTTP_USER_AGENT = Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/58.0.3029.110 Safari/537.36
HTTP_X_REQUESTED_WITH = XMLHttpRequest
PATH_INFO = /dovote/1/SomePath
QUERY_STRING = name=xxxxx&time=yyyyyy
RAW_URI = /dovote/1/SomePath?name=xxxxx&time=yyyyyy
REMOTE_ADDR = 127.0.0.1
REMOTE_PORT = 39968
REQUEST_METHOD = GET
SCRIPT_NAME = 
SERVER_NAME = 0.0.0.0
SERVER_PORT = 6543
SERVER_PROTOCOL = HTTP/1.1
SERVER_SOFTWARE = gunicorn/19.7.1
gunicorn.socket = <socket._socketobject object at 0x7f090e131440>
wsgi.errors = <gunicorn.http.wsgi.WSGIErrorsWrapper object at 0x7f09082e14d0>
wsgi.file_wrapper = <class 'gunicorn.http.wsgi.FileWrapper'>
wsgi.input = <gunicorn.http.body.Body object at 0x7f0908279d90>
wsgi.multiprocess = False
wsgi.multithread = False
wsgi.run_once = False
wsgi.url_scheme = http
wsgi.version = (1, 0)

As you can see, the header 'HTTP_X_REQUESTED_WITH = XMLHttpRequest' is what I wanted to detect an ajax request.

Eric
  • 4,821
  • 6
  • 33
  • 60