Post JSON to Python CGI












8















I have got Apache2 Installed and Python working.



I am having a problem though. I have two pages.



One a Python Page and the other an Html Page with JQuery



Can someone please tell me how I can get my ajax post to work correctly.



<html>
<head>

</head>
<body>
<script>
$(function()
{
alert('Im going to start processing');

$.ajax({
url: "saveList.py",
type: "post",
data: {'param':{"hello":"world"}},
dataType: "application/json",
success : function(response)
{
alert(response);
}
});
});
</script>
</body>
</html>


And the Python Code



import sys
import json

def index(req):
result = {'success':'true','message':'The Command Completed Successfully'};

data = sys.stdin.read();

myjson = json.loads(data);

return str(myjson);









share|improve this question

























  • Presumably, nothing happens? Please tell us the problems you see.

    – Martijn Pieters
    May 23 '12 at 11:03











  • Are you posting a JSON or a JSON-string which is percentile-encoded?

    – UltraInstinct
    May 23 '12 at 11:37











  • I just want it so it shows me what I posted in so I have an idea that it actually works. Insted of it at present returning "null"

    – TheMonkeyMan
    May 23 '12 at 13:14











  • @Deano Well, your question first was not very clear. Now you can check the updated version of my answer. It should work.

    – VisioN
    May 23 '12 at 13:52











  • Why is there a semicolon after each statement in the python code above? An error, I assume?

    – Sudipta Chatterjee
    Jan 8 '13 at 23:23
















8















I have got Apache2 Installed and Python working.



I am having a problem though. I have two pages.



One a Python Page and the other an Html Page with JQuery



Can someone please tell me how I can get my ajax post to work correctly.



<html>
<head>

</head>
<body>
<script>
$(function()
{
alert('Im going to start processing');

$.ajax({
url: "saveList.py",
type: "post",
data: {'param':{"hello":"world"}},
dataType: "application/json",
success : function(response)
{
alert(response);
}
});
});
</script>
</body>
</html>


And the Python Code



import sys
import json

def index(req):
result = {'success':'true','message':'The Command Completed Successfully'};

data = sys.stdin.read();

myjson = json.loads(data);

return str(myjson);









share|improve this question

























  • Presumably, nothing happens? Please tell us the problems you see.

    – Martijn Pieters
    May 23 '12 at 11:03











  • Are you posting a JSON or a JSON-string which is percentile-encoded?

    – UltraInstinct
    May 23 '12 at 11:37











  • I just want it so it shows me what I posted in so I have an idea that it actually works. Insted of it at present returning "null"

    – TheMonkeyMan
    May 23 '12 at 13:14











  • @Deano Well, your question first was not very clear. Now you can check the updated version of my answer. It should work.

    – VisioN
    May 23 '12 at 13:52











  • Why is there a semicolon after each statement in the python code above? An error, I assume?

    – Sudipta Chatterjee
    Jan 8 '13 at 23:23














8












8








8


4






I have got Apache2 Installed and Python working.



I am having a problem though. I have two pages.



One a Python Page and the other an Html Page with JQuery



Can someone please tell me how I can get my ajax post to work correctly.



<html>
<head>

</head>
<body>
<script>
$(function()
{
alert('Im going to start processing');

$.ajax({
url: "saveList.py",
type: "post",
data: {'param':{"hello":"world"}},
dataType: "application/json",
success : function(response)
{
alert(response);
}
});
});
</script>
</body>
</html>


And the Python Code



import sys
import json

def index(req):
result = {'success':'true','message':'The Command Completed Successfully'};

data = sys.stdin.read();

myjson = json.loads(data);

return str(myjson);









share|improve this question
















I have got Apache2 Installed and Python working.



I am having a problem though. I have two pages.



One a Python Page and the other an Html Page with JQuery



Can someone please tell me how I can get my ajax post to work correctly.



<html>
<head>

</head>
<body>
<script>
$(function()
{
alert('Im going to start processing');

$.ajax({
url: "saveList.py",
type: "post",
data: {'param':{"hello":"world"}},
dataType: "application/json",
success : function(response)
{
alert(response);
}
});
});
</script>
</body>
</html>


And the Python Code



import sys
import json

def index(req):
result = {'success':'true','message':'The Command Completed Successfully'};

data = sys.stdin.read();

myjson = json.loads(data);

return str(myjson);






jquery python html ajax






share|improve this question















share|improve this question













share|improve this question




share|improve this question








edited May 23 '12 at 13:10







TheMonkeyMan

















asked May 23 '12 at 10:59









TheMonkeyManTheMonkeyMan

2,95151833




2,95151833













  • Presumably, nothing happens? Please tell us the problems you see.

    – Martijn Pieters
    May 23 '12 at 11:03











  • Are you posting a JSON or a JSON-string which is percentile-encoded?

    – UltraInstinct
    May 23 '12 at 11:37











  • I just want it so it shows me what I posted in so I have an idea that it actually works. Insted of it at present returning "null"

    – TheMonkeyMan
    May 23 '12 at 13:14











  • @Deano Well, your question first was not very clear. Now you can check the updated version of my answer. It should work.

    – VisioN
    May 23 '12 at 13:52











  • Why is there a semicolon after each statement in the python code above? An error, I assume?

    – Sudipta Chatterjee
    Jan 8 '13 at 23:23



















  • Presumably, nothing happens? Please tell us the problems you see.

    – Martijn Pieters
    May 23 '12 at 11:03











  • Are you posting a JSON or a JSON-string which is percentile-encoded?

    – UltraInstinct
    May 23 '12 at 11:37











  • I just want it so it shows me what I posted in so I have an idea that it actually works. Insted of it at present returning "null"

    – TheMonkeyMan
    May 23 '12 at 13:14











  • @Deano Well, your question first was not very clear. Now you can check the updated version of my answer. It should work.

    – VisioN
    May 23 '12 at 13:52











  • Why is there a semicolon after each statement in the python code above? An error, I assume?

    – Sudipta Chatterjee
    Jan 8 '13 at 23:23

















Presumably, nothing happens? Please tell us the problems you see.

– Martijn Pieters
May 23 '12 at 11:03





Presumably, nothing happens? Please tell us the problems you see.

– Martijn Pieters
May 23 '12 at 11:03













Are you posting a JSON or a JSON-string which is percentile-encoded?

– UltraInstinct
May 23 '12 at 11:37





Are you posting a JSON or a JSON-string which is percentile-encoded?

– UltraInstinct
May 23 '12 at 11:37













I just want it so it shows me what I posted in so I have an idea that it actually works. Insted of it at present returning "null"

– TheMonkeyMan
May 23 '12 at 13:14





I just want it so it shows me what I posted in so I have an idea that it actually works. Insted of it at present returning "null"

– TheMonkeyMan
May 23 '12 at 13:14













@Deano Well, your question first was not very clear. Now you can check the updated version of my answer. It should work.

– VisioN
May 23 '12 at 13:52





@Deano Well, your question first was not very clear. Now you can check the updated version of my answer. It should work.

– VisioN
May 23 '12 at 13:52













Why is there a semicolon after each statement in the python code above? An error, I assume?

– Sudipta Chatterjee
Jan 8 '13 at 23:23





Why is there a semicolon after each statement in the python code above? An error, I assume?

– Sudipta Chatterjee
Jan 8 '13 at 23:23












2 Answers
2






active

oldest

votes


















10














OK, let's move to your updated question.



First, you should pass Ajax data property in string representation. Then, since you mix dataType and contentType properties, change dataType value to "json":



$.ajax({
url: "saveList.py",
type: "post",
data: JSON.stringify({'param':{"hello":"world"}}),
dataType: "json",
success: function(response) {
alert(response);
}
});


Finally, modify your code a bit to work with JSON request as follows:



#!/usr/bin/python

import sys, json

result = {'success':'true','message':'The Command Completed Successfully'};

myjson = json.load(sys.stdin)
# Do something with 'myjson' object

print 'Content-Type: application/jsonnn'
print json.dumps(result) # or "json.dump(result, sys.stdout)"


As a result, in the success handler of Ajax request you will receive object with success and message properties.






share|improve this answer





















  • 1





    He is posting an application/json and not application/x-www-form-urlencoded. His way of reading from stdin is correct (IMO). I suppose problem is elsewhere.

    – UltraInstinct
    May 23 '12 at 11:34













  • @Thrustmaster What are you talking about? Default contentType for standard Ajax request is exaclty application/x-www-form-urlencoded. Why do you need to use something else?

    – VisioN
    May 23 '12 at 11:44






  • 1





    OP is (from his code) doing a HTTP/POST with JSON-string in the body of HTTP. The content-type will be application/json which would need to be set using $.ajax({contentType:"application/json"},...). What you suggested up there, is to url-encode JSON string, which, IMO, is not OP is doing (since he is correctly reading from stdin on the server-side for that)

    – UltraInstinct
    May 23 '12 at 11:50






  • 1





    First, are you sure that he reads from stdin correctly? HTTP request is not the same as input from the console. Next, he can easily send not a string but data : { first : 1, next : 2 } and get both first and next with form on server-side. What is the problem? Then, where have you taken that OP sends application/json as content type? Why to do it? OP simply doesn't know how to handle post requests from Ajax with plain Python CGI. I think you overdo it.

    – VisioN
    May 23 '12 at 11:54








  • 1





    I have been searching the web to find how to make cgi recognise raw strings NOT sent from an html form but found this solution..my 3 days of late night sleep came to an end..thank you

    – repzero
    Nov 27 '15 at 2:04



















0














You should read json data like this:



#!/usr/bin/env python3

import os
import sys
import json

content_len = int(os.environ["CONTENT_LENGTH"])

req_body = sys.stdin.read(content_len)
my_dict = json.loads(req_body)




With the following code, you can run into problems:



 myjson = json.load(sys.stdin)


or written less succinctly:



requ_body = sys.stdin.read()
my_dict = json.load(requ_body)


That does work for me when my cgi script is on an apache server, but you can't count on that working in general--as I found out when my cgi script was on another server. According to the cgi spec:



RFC 3875                    CGI Version 1.1                 October 2004


4.2. Request Message-Body

Request data is accessed by the script in a system-defined method;
unless defined otherwise, this will be by reading the 'standard
input' file descriptor or file handle.

Request-Data = [ request-body ] [ extension-data ]
request-body = <CONTENT_LENGTH>OCTET
extension-data = *OCTET

A request-body is supplied with the request if the CONTENT_LENGTH is
not NULL. The server MUST make at least that many bytes available
for the script to read. The server MAY signal an end-of-file
condition after CONTENT_LENGTH bytes have been read or it MAY supply
extension data. Therefore, the script MUST NOT attempt to read more
than CONTENT_LENGTH bytes, even if more data is available. However,
it is not obliged to read any of the data.


The key line is:




the script MUST NOT attempt to read more
than CONTENT_LENGTH bytes, even if more data is available.




Apparently, apache sends an eof signal to the cgi script immediately after sending the request body to the cgi script, which causes sys.stdin.read() to return. But according to the cgi spec, a server is not required to send an eof signal after the body of the request, and I found that my cgi script was hanging on sys.stdin.read()--when my script was on another server, which eventually caused a timeout error.



Therefore, in order to read in json data in the general case, you should do this:



content_len = int(os.environ["CONTENT_LENGTH"])

req_body = sys.stdin.read(content_len)
my_dict = json.loads(req_body)


The server sets a bunch of environment variables for cgi scripts, which contain header information, one of which is CONTENT_LENGTH.



Here is what a failed curl request looked like when I used myjson = json.load(sys.stdin):



-v      verbose output
-H specify one header
--data implicitly specifies a POST request

Note that curl automatically calculates a Content-Length header
for you.




~$ curl -v 
> -H 'Content-Type: application/json'
> --data '{"a": 1, "b": 2}'
> http://localhost:65451/cgi-bin/1.py

* Trying ::1...
* TCP_NODELAY set
* Connection failed
* connect to ::1 port 65451 failed: Connection refused
* Trying 127.0.0.1...
* TCP_NODELAY set
* Connected to localhost (127.0.0.1) port 65451 (#0)
> POST /cgi-bin/1.py HTTP/1.1
> Host: localhost:65451
> User-Agent: curl/7.58.0
> Accept: */*
> Content-Type: application/json
> Content-Length: 16
>
* upload completely sent off: 16 out of 16 bytes

=== hung here for about 5 seconds ====

< HTTP/1.1 504 Gateway Time-out
< Date: Thu, 08 Mar 2018 17:53:30 GMT
< Content-Type: text/html
< Server: inets/6.4.5
* no chunk, no close, no size. Assume close to signal end
<
* Closing connection 0





share|improve this answer

























    Your Answer






    StackExchange.ifUsing("editor", function () {
    StackExchange.using("externalEditor", function () {
    StackExchange.using("snippets", function () {
    StackExchange.snippets.init();
    });
    });
    }, "code-snippets");

    StackExchange.ready(function() {
    var channelOptions = {
    tags: "".split(" "),
    id: "1"
    };
    initTagRenderer("".split(" "), "".split(" "), channelOptions);

    StackExchange.using("externalEditor", function() {
    // Have to fire editor after snippets, if snippets enabled
    if (StackExchange.settings.snippets.snippetsEnabled) {
    StackExchange.using("snippets", function() {
    createEditor();
    });
    }
    else {
    createEditor();
    }
    });

    function createEditor() {
    StackExchange.prepareEditor({
    heartbeatType: 'answer',
    autoActivateHeartbeat: false,
    convertImagesToLinks: true,
    noModals: true,
    showLowRepImageUploadWarning: true,
    reputationToPostImages: 10,
    bindNavPrevention: true,
    postfix: "",
    imageUploader: {
    brandingHtml: "Powered by u003ca class="icon-imgur-white" href="https://imgur.com/"u003eu003c/au003e",
    contentPolicyHtml: "User contributions licensed under u003ca href="https://creativecommons.org/licenses/by-sa/3.0/"u003ecc by-sa 3.0 with attribution requiredu003c/au003e u003ca href="https://stackoverflow.com/legal/content-policy"u003e(content policy)u003c/au003e",
    allowUrls: true
    },
    onDemand: true,
    discardSelector: ".discard-answer"
    ,immediatelyShowMarkdownHelp:true
    });


    }
    });














    draft saved

    draft discarded


















    StackExchange.ready(
    function () {
    StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f10718572%2fpost-json-to-python-cgi%23new-answer', 'question_page');
    }
    );

    Post as a guest















    Required, but never shown

























    2 Answers
    2






    active

    oldest

    votes








    2 Answers
    2






    active

    oldest

    votes









    active

    oldest

    votes






    active

    oldest

    votes









    10














    OK, let's move to your updated question.



    First, you should pass Ajax data property in string representation. Then, since you mix dataType and contentType properties, change dataType value to "json":



    $.ajax({
    url: "saveList.py",
    type: "post",
    data: JSON.stringify({'param':{"hello":"world"}}),
    dataType: "json",
    success: function(response) {
    alert(response);
    }
    });


    Finally, modify your code a bit to work with JSON request as follows:



    #!/usr/bin/python

    import sys, json

    result = {'success':'true','message':'The Command Completed Successfully'};

    myjson = json.load(sys.stdin)
    # Do something with 'myjson' object

    print 'Content-Type: application/jsonnn'
    print json.dumps(result) # or "json.dump(result, sys.stdout)"


    As a result, in the success handler of Ajax request you will receive object with success and message properties.






    share|improve this answer





















    • 1





      He is posting an application/json and not application/x-www-form-urlencoded. His way of reading from stdin is correct (IMO). I suppose problem is elsewhere.

      – UltraInstinct
      May 23 '12 at 11:34













    • @Thrustmaster What are you talking about? Default contentType for standard Ajax request is exaclty application/x-www-form-urlencoded. Why do you need to use something else?

      – VisioN
      May 23 '12 at 11:44






    • 1





      OP is (from his code) doing a HTTP/POST with JSON-string in the body of HTTP. The content-type will be application/json which would need to be set using $.ajax({contentType:"application/json"},...). What you suggested up there, is to url-encode JSON string, which, IMO, is not OP is doing (since he is correctly reading from stdin on the server-side for that)

      – UltraInstinct
      May 23 '12 at 11:50






    • 1





      First, are you sure that he reads from stdin correctly? HTTP request is not the same as input from the console. Next, he can easily send not a string but data : { first : 1, next : 2 } and get both first and next with form on server-side. What is the problem? Then, where have you taken that OP sends application/json as content type? Why to do it? OP simply doesn't know how to handle post requests from Ajax with plain Python CGI. I think you overdo it.

      – VisioN
      May 23 '12 at 11:54








    • 1





      I have been searching the web to find how to make cgi recognise raw strings NOT sent from an html form but found this solution..my 3 days of late night sleep came to an end..thank you

      – repzero
      Nov 27 '15 at 2:04
















    10














    OK, let's move to your updated question.



    First, you should pass Ajax data property in string representation. Then, since you mix dataType and contentType properties, change dataType value to "json":



    $.ajax({
    url: "saveList.py",
    type: "post",
    data: JSON.stringify({'param':{"hello":"world"}}),
    dataType: "json",
    success: function(response) {
    alert(response);
    }
    });


    Finally, modify your code a bit to work with JSON request as follows:



    #!/usr/bin/python

    import sys, json

    result = {'success':'true','message':'The Command Completed Successfully'};

    myjson = json.load(sys.stdin)
    # Do something with 'myjson' object

    print 'Content-Type: application/jsonnn'
    print json.dumps(result) # or "json.dump(result, sys.stdout)"


    As a result, in the success handler of Ajax request you will receive object with success and message properties.






    share|improve this answer





















    • 1





      He is posting an application/json and not application/x-www-form-urlencoded. His way of reading from stdin is correct (IMO). I suppose problem is elsewhere.

      – UltraInstinct
      May 23 '12 at 11:34













    • @Thrustmaster What are you talking about? Default contentType for standard Ajax request is exaclty application/x-www-form-urlencoded. Why do you need to use something else?

      – VisioN
      May 23 '12 at 11:44






    • 1





      OP is (from his code) doing a HTTP/POST with JSON-string in the body of HTTP. The content-type will be application/json which would need to be set using $.ajax({contentType:"application/json"},...). What you suggested up there, is to url-encode JSON string, which, IMO, is not OP is doing (since he is correctly reading from stdin on the server-side for that)

      – UltraInstinct
      May 23 '12 at 11:50






    • 1





      First, are you sure that he reads from stdin correctly? HTTP request is not the same as input from the console. Next, he can easily send not a string but data : { first : 1, next : 2 } and get both first and next with form on server-side. What is the problem? Then, where have you taken that OP sends application/json as content type? Why to do it? OP simply doesn't know how to handle post requests from Ajax with plain Python CGI. I think you overdo it.

      – VisioN
      May 23 '12 at 11:54








    • 1





      I have been searching the web to find how to make cgi recognise raw strings NOT sent from an html form but found this solution..my 3 days of late night sleep came to an end..thank you

      – repzero
      Nov 27 '15 at 2:04














    10












    10








    10







    OK, let's move to your updated question.



    First, you should pass Ajax data property in string representation. Then, since you mix dataType and contentType properties, change dataType value to "json":



    $.ajax({
    url: "saveList.py",
    type: "post",
    data: JSON.stringify({'param':{"hello":"world"}}),
    dataType: "json",
    success: function(response) {
    alert(response);
    }
    });


    Finally, modify your code a bit to work with JSON request as follows:



    #!/usr/bin/python

    import sys, json

    result = {'success':'true','message':'The Command Completed Successfully'};

    myjson = json.load(sys.stdin)
    # Do something with 'myjson' object

    print 'Content-Type: application/jsonnn'
    print json.dumps(result) # or "json.dump(result, sys.stdout)"


    As a result, in the success handler of Ajax request you will receive object with success and message properties.






    share|improve this answer















    OK, let's move to your updated question.



    First, you should pass Ajax data property in string representation. Then, since you mix dataType and contentType properties, change dataType value to "json":



    $.ajax({
    url: "saveList.py",
    type: "post",
    data: JSON.stringify({'param':{"hello":"world"}}),
    dataType: "json",
    success: function(response) {
    alert(response);
    }
    });


    Finally, modify your code a bit to work with JSON request as follows:



    #!/usr/bin/python

    import sys, json

    result = {'success':'true','message':'The Command Completed Successfully'};

    myjson = json.load(sys.stdin)
    # Do something with 'myjson' object

    print 'Content-Type: application/jsonnn'
    print json.dumps(result) # or "json.dump(result, sys.stdout)"


    As a result, in the success handler of Ajax request you will receive object with success and message properties.







    share|improve this answer














    share|improve this answer



    share|improve this answer








    edited May 23 '12 at 13:51

























    answered May 23 '12 at 11:20









    VisioNVisioN

    111k24212226




    111k24212226








    • 1





      He is posting an application/json and not application/x-www-form-urlencoded. His way of reading from stdin is correct (IMO). I suppose problem is elsewhere.

      – UltraInstinct
      May 23 '12 at 11:34













    • @Thrustmaster What are you talking about? Default contentType for standard Ajax request is exaclty application/x-www-form-urlencoded. Why do you need to use something else?

      – VisioN
      May 23 '12 at 11:44






    • 1





      OP is (from his code) doing a HTTP/POST with JSON-string in the body of HTTP. The content-type will be application/json which would need to be set using $.ajax({contentType:"application/json"},...). What you suggested up there, is to url-encode JSON string, which, IMO, is not OP is doing (since he is correctly reading from stdin on the server-side for that)

      – UltraInstinct
      May 23 '12 at 11:50






    • 1





      First, are you sure that he reads from stdin correctly? HTTP request is not the same as input from the console. Next, he can easily send not a string but data : { first : 1, next : 2 } and get both first and next with form on server-side. What is the problem? Then, where have you taken that OP sends application/json as content type? Why to do it? OP simply doesn't know how to handle post requests from Ajax with plain Python CGI. I think you overdo it.

      – VisioN
      May 23 '12 at 11:54








    • 1





      I have been searching the web to find how to make cgi recognise raw strings NOT sent from an html form but found this solution..my 3 days of late night sleep came to an end..thank you

      – repzero
      Nov 27 '15 at 2:04














    • 1





      He is posting an application/json and not application/x-www-form-urlencoded. His way of reading from stdin is correct (IMO). I suppose problem is elsewhere.

      – UltraInstinct
      May 23 '12 at 11:34













    • @Thrustmaster What are you talking about? Default contentType for standard Ajax request is exaclty application/x-www-form-urlencoded. Why do you need to use something else?

      – VisioN
      May 23 '12 at 11:44






    • 1





      OP is (from his code) doing a HTTP/POST with JSON-string in the body of HTTP. The content-type will be application/json which would need to be set using $.ajax({contentType:"application/json"},...). What you suggested up there, is to url-encode JSON string, which, IMO, is not OP is doing (since he is correctly reading from stdin on the server-side for that)

      – UltraInstinct
      May 23 '12 at 11:50






    • 1





      First, are you sure that he reads from stdin correctly? HTTP request is not the same as input from the console. Next, he can easily send not a string but data : { first : 1, next : 2 } and get both first and next with form on server-side. What is the problem? Then, where have you taken that OP sends application/json as content type? Why to do it? OP simply doesn't know how to handle post requests from Ajax with plain Python CGI. I think you overdo it.

      – VisioN
      May 23 '12 at 11:54








    • 1





      I have been searching the web to find how to make cgi recognise raw strings NOT sent from an html form but found this solution..my 3 days of late night sleep came to an end..thank you

      – repzero
      Nov 27 '15 at 2:04








    1




    1





    He is posting an application/json and not application/x-www-form-urlencoded. His way of reading from stdin is correct (IMO). I suppose problem is elsewhere.

    – UltraInstinct
    May 23 '12 at 11:34







    He is posting an application/json and not application/x-www-form-urlencoded. His way of reading from stdin is correct (IMO). I suppose problem is elsewhere.

    – UltraInstinct
    May 23 '12 at 11:34















    @Thrustmaster What are you talking about? Default contentType for standard Ajax request is exaclty application/x-www-form-urlencoded. Why do you need to use something else?

    – VisioN
    May 23 '12 at 11:44





    @Thrustmaster What are you talking about? Default contentType for standard Ajax request is exaclty application/x-www-form-urlencoded. Why do you need to use something else?

    – VisioN
    May 23 '12 at 11:44




    1




    1





    OP is (from his code) doing a HTTP/POST with JSON-string in the body of HTTP. The content-type will be application/json which would need to be set using $.ajax({contentType:"application/json"},...). What you suggested up there, is to url-encode JSON string, which, IMO, is not OP is doing (since he is correctly reading from stdin on the server-side for that)

    – UltraInstinct
    May 23 '12 at 11:50





    OP is (from his code) doing a HTTP/POST with JSON-string in the body of HTTP. The content-type will be application/json which would need to be set using $.ajax({contentType:"application/json"},...). What you suggested up there, is to url-encode JSON string, which, IMO, is not OP is doing (since he is correctly reading from stdin on the server-side for that)

    – UltraInstinct
    May 23 '12 at 11:50




    1




    1





    First, are you sure that he reads from stdin correctly? HTTP request is not the same as input from the console. Next, he can easily send not a string but data : { first : 1, next : 2 } and get both first and next with form on server-side. What is the problem? Then, where have you taken that OP sends application/json as content type? Why to do it? OP simply doesn't know how to handle post requests from Ajax with plain Python CGI. I think you overdo it.

    – VisioN
    May 23 '12 at 11:54







    First, are you sure that he reads from stdin correctly? HTTP request is not the same as input from the console. Next, he can easily send not a string but data : { first : 1, next : 2 } and get both first and next with form on server-side. What is the problem? Then, where have you taken that OP sends application/json as content type? Why to do it? OP simply doesn't know how to handle post requests from Ajax with plain Python CGI. I think you overdo it.

    – VisioN
    May 23 '12 at 11:54






    1




    1





    I have been searching the web to find how to make cgi recognise raw strings NOT sent from an html form but found this solution..my 3 days of late night sleep came to an end..thank you

    – repzero
    Nov 27 '15 at 2:04





    I have been searching the web to find how to make cgi recognise raw strings NOT sent from an html form but found this solution..my 3 days of late night sleep came to an end..thank you

    – repzero
    Nov 27 '15 at 2:04













    0














    You should read json data like this:



    #!/usr/bin/env python3

    import os
    import sys
    import json

    content_len = int(os.environ["CONTENT_LENGTH"])

    req_body = sys.stdin.read(content_len)
    my_dict = json.loads(req_body)




    With the following code, you can run into problems:



     myjson = json.load(sys.stdin)


    or written less succinctly:



    requ_body = sys.stdin.read()
    my_dict = json.load(requ_body)


    That does work for me when my cgi script is on an apache server, but you can't count on that working in general--as I found out when my cgi script was on another server. According to the cgi spec:



    RFC 3875                    CGI Version 1.1                 October 2004


    4.2. Request Message-Body

    Request data is accessed by the script in a system-defined method;
    unless defined otherwise, this will be by reading the 'standard
    input' file descriptor or file handle.

    Request-Data = [ request-body ] [ extension-data ]
    request-body = <CONTENT_LENGTH>OCTET
    extension-data = *OCTET

    A request-body is supplied with the request if the CONTENT_LENGTH is
    not NULL. The server MUST make at least that many bytes available
    for the script to read. The server MAY signal an end-of-file
    condition after CONTENT_LENGTH bytes have been read or it MAY supply
    extension data. Therefore, the script MUST NOT attempt to read more
    than CONTENT_LENGTH bytes, even if more data is available. However,
    it is not obliged to read any of the data.


    The key line is:




    the script MUST NOT attempt to read more
    than CONTENT_LENGTH bytes, even if more data is available.




    Apparently, apache sends an eof signal to the cgi script immediately after sending the request body to the cgi script, which causes sys.stdin.read() to return. But according to the cgi spec, a server is not required to send an eof signal after the body of the request, and I found that my cgi script was hanging on sys.stdin.read()--when my script was on another server, which eventually caused a timeout error.



    Therefore, in order to read in json data in the general case, you should do this:



    content_len = int(os.environ["CONTENT_LENGTH"])

    req_body = sys.stdin.read(content_len)
    my_dict = json.loads(req_body)


    The server sets a bunch of environment variables for cgi scripts, which contain header information, one of which is CONTENT_LENGTH.



    Here is what a failed curl request looked like when I used myjson = json.load(sys.stdin):



    -v      verbose output
    -H specify one header
    --data implicitly specifies a POST request

    Note that curl automatically calculates a Content-Length header
    for you.




    ~$ curl -v 
    > -H 'Content-Type: application/json'
    > --data '{"a": 1, "b": 2}'
    > http://localhost:65451/cgi-bin/1.py

    * Trying ::1...
    * TCP_NODELAY set
    * Connection failed
    * connect to ::1 port 65451 failed: Connection refused
    * Trying 127.0.0.1...
    * TCP_NODELAY set
    * Connected to localhost (127.0.0.1) port 65451 (#0)
    > POST /cgi-bin/1.py HTTP/1.1
    > Host: localhost:65451
    > User-Agent: curl/7.58.0
    > Accept: */*
    > Content-Type: application/json
    > Content-Length: 16
    >
    * upload completely sent off: 16 out of 16 bytes

    === hung here for about 5 seconds ====

    < HTTP/1.1 504 Gateway Time-out
    < Date: Thu, 08 Mar 2018 17:53:30 GMT
    < Content-Type: text/html
    < Server: inets/6.4.5
    * no chunk, no close, no size. Assume close to signal end
    <
    * Closing connection 0





    share|improve this answer






























      0














      You should read json data like this:



      #!/usr/bin/env python3

      import os
      import sys
      import json

      content_len = int(os.environ["CONTENT_LENGTH"])

      req_body = sys.stdin.read(content_len)
      my_dict = json.loads(req_body)




      With the following code, you can run into problems:



       myjson = json.load(sys.stdin)


      or written less succinctly:



      requ_body = sys.stdin.read()
      my_dict = json.load(requ_body)


      That does work for me when my cgi script is on an apache server, but you can't count on that working in general--as I found out when my cgi script was on another server. According to the cgi spec:



      RFC 3875                    CGI Version 1.1                 October 2004


      4.2. Request Message-Body

      Request data is accessed by the script in a system-defined method;
      unless defined otherwise, this will be by reading the 'standard
      input' file descriptor or file handle.

      Request-Data = [ request-body ] [ extension-data ]
      request-body = <CONTENT_LENGTH>OCTET
      extension-data = *OCTET

      A request-body is supplied with the request if the CONTENT_LENGTH is
      not NULL. The server MUST make at least that many bytes available
      for the script to read. The server MAY signal an end-of-file
      condition after CONTENT_LENGTH bytes have been read or it MAY supply
      extension data. Therefore, the script MUST NOT attempt to read more
      than CONTENT_LENGTH bytes, even if more data is available. However,
      it is not obliged to read any of the data.


      The key line is:




      the script MUST NOT attempt to read more
      than CONTENT_LENGTH bytes, even if more data is available.




      Apparently, apache sends an eof signal to the cgi script immediately after sending the request body to the cgi script, which causes sys.stdin.read() to return. But according to the cgi spec, a server is not required to send an eof signal after the body of the request, and I found that my cgi script was hanging on sys.stdin.read()--when my script was on another server, which eventually caused a timeout error.



      Therefore, in order to read in json data in the general case, you should do this:



      content_len = int(os.environ["CONTENT_LENGTH"])

      req_body = sys.stdin.read(content_len)
      my_dict = json.loads(req_body)


      The server sets a bunch of environment variables for cgi scripts, which contain header information, one of which is CONTENT_LENGTH.



      Here is what a failed curl request looked like when I used myjson = json.load(sys.stdin):



      -v      verbose output
      -H specify one header
      --data implicitly specifies a POST request

      Note that curl automatically calculates a Content-Length header
      for you.




      ~$ curl -v 
      > -H 'Content-Type: application/json'
      > --data '{"a": 1, "b": 2}'
      > http://localhost:65451/cgi-bin/1.py

      * Trying ::1...
      * TCP_NODELAY set
      * Connection failed
      * connect to ::1 port 65451 failed: Connection refused
      * Trying 127.0.0.1...
      * TCP_NODELAY set
      * Connected to localhost (127.0.0.1) port 65451 (#0)
      > POST /cgi-bin/1.py HTTP/1.1
      > Host: localhost:65451
      > User-Agent: curl/7.58.0
      > Accept: */*
      > Content-Type: application/json
      > Content-Length: 16
      >
      * upload completely sent off: 16 out of 16 bytes

      === hung here for about 5 seconds ====

      < HTTP/1.1 504 Gateway Time-out
      < Date: Thu, 08 Mar 2018 17:53:30 GMT
      < Content-Type: text/html
      < Server: inets/6.4.5
      * no chunk, no close, no size. Assume close to signal end
      <
      * Closing connection 0





      share|improve this answer




























        0












        0








        0







        You should read json data like this:



        #!/usr/bin/env python3

        import os
        import sys
        import json

        content_len = int(os.environ["CONTENT_LENGTH"])

        req_body = sys.stdin.read(content_len)
        my_dict = json.loads(req_body)




        With the following code, you can run into problems:



         myjson = json.load(sys.stdin)


        or written less succinctly:



        requ_body = sys.stdin.read()
        my_dict = json.load(requ_body)


        That does work for me when my cgi script is on an apache server, but you can't count on that working in general--as I found out when my cgi script was on another server. According to the cgi spec:



        RFC 3875                    CGI Version 1.1                 October 2004


        4.2. Request Message-Body

        Request data is accessed by the script in a system-defined method;
        unless defined otherwise, this will be by reading the 'standard
        input' file descriptor or file handle.

        Request-Data = [ request-body ] [ extension-data ]
        request-body = <CONTENT_LENGTH>OCTET
        extension-data = *OCTET

        A request-body is supplied with the request if the CONTENT_LENGTH is
        not NULL. The server MUST make at least that many bytes available
        for the script to read. The server MAY signal an end-of-file
        condition after CONTENT_LENGTH bytes have been read or it MAY supply
        extension data. Therefore, the script MUST NOT attempt to read more
        than CONTENT_LENGTH bytes, even if more data is available. However,
        it is not obliged to read any of the data.


        The key line is:




        the script MUST NOT attempt to read more
        than CONTENT_LENGTH bytes, even if more data is available.




        Apparently, apache sends an eof signal to the cgi script immediately after sending the request body to the cgi script, which causes sys.stdin.read() to return. But according to the cgi spec, a server is not required to send an eof signal after the body of the request, and I found that my cgi script was hanging on sys.stdin.read()--when my script was on another server, which eventually caused a timeout error.



        Therefore, in order to read in json data in the general case, you should do this:



        content_len = int(os.environ["CONTENT_LENGTH"])

        req_body = sys.stdin.read(content_len)
        my_dict = json.loads(req_body)


        The server sets a bunch of environment variables for cgi scripts, which contain header information, one of which is CONTENT_LENGTH.



        Here is what a failed curl request looked like when I used myjson = json.load(sys.stdin):



        -v      verbose output
        -H specify one header
        --data implicitly specifies a POST request

        Note that curl automatically calculates a Content-Length header
        for you.




        ~$ curl -v 
        > -H 'Content-Type: application/json'
        > --data '{"a": 1, "b": 2}'
        > http://localhost:65451/cgi-bin/1.py

        * Trying ::1...
        * TCP_NODELAY set
        * Connection failed
        * connect to ::1 port 65451 failed: Connection refused
        * Trying 127.0.0.1...
        * TCP_NODELAY set
        * Connected to localhost (127.0.0.1) port 65451 (#0)
        > POST /cgi-bin/1.py HTTP/1.1
        > Host: localhost:65451
        > User-Agent: curl/7.58.0
        > Accept: */*
        > Content-Type: application/json
        > Content-Length: 16
        >
        * upload completely sent off: 16 out of 16 bytes

        === hung here for about 5 seconds ====

        < HTTP/1.1 504 Gateway Time-out
        < Date: Thu, 08 Mar 2018 17:53:30 GMT
        < Content-Type: text/html
        < Server: inets/6.4.5
        * no chunk, no close, no size. Assume close to signal end
        <
        * Closing connection 0





        share|improve this answer















        You should read json data like this:



        #!/usr/bin/env python3

        import os
        import sys
        import json

        content_len = int(os.environ["CONTENT_LENGTH"])

        req_body = sys.stdin.read(content_len)
        my_dict = json.loads(req_body)




        With the following code, you can run into problems:



         myjson = json.load(sys.stdin)


        or written less succinctly:



        requ_body = sys.stdin.read()
        my_dict = json.load(requ_body)


        That does work for me when my cgi script is on an apache server, but you can't count on that working in general--as I found out when my cgi script was on another server. According to the cgi spec:



        RFC 3875                    CGI Version 1.1                 October 2004


        4.2. Request Message-Body

        Request data is accessed by the script in a system-defined method;
        unless defined otherwise, this will be by reading the 'standard
        input' file descriptor or file handle.

        Request-Data = [ request-body ] [ extension-data ]
        request-body = <CONTENT_LENGTH>OCTET
        extension-data = *OCTET

        A request-body is supplied with the request if the CONTENT_LENGTH is
        not NULL. The server MUST make at least that many bytes available
        for the script to read. The server MAY signal an end-of-file
        condition after CONTENT_LENGTH bytes have been read or it MAY supply
        extension data. Therefore, the script MUST NOT attempt to read more
        than CONTENT_LENGTH bytes, even if more data is available. However,
        it is not obliged to read any of the data.


        The key line is:




        the script MUST NOT attempt to read more
        than CONTENT_LENGTH bytes, even if more data is available.




        Apparently, apache sends an eof signal to the cgi script immediately after sending the request body to the cgi script, which causes sys.stdin.read() to return. But according to the cgi spec, a server is not required to send an eof signal after the body of the request, and I found that my cgi script was hanging on sys.stdin.read()--when my script was on another server, which eventually caused a timeout error.



        Therefore, in order to read in json data in the general case, you should do this:



        content_len = int(os.environ["CONTENT_LENGTH"])

        req_body = sys.stdin.read(content_len)
        my_dict = json.loads(req_body)


        The server sets a bunch of environment variables for cgi scripts, which contain header information, one of which is CONTENT_LENGTH.



        Here is what a failed curl request looked like when I used myjson = json.load(sys.stdin):



        -v      verbose output
        -H specify one header
        --data implicitly specifies a POST request

        Note that curl automatically calculates a Content-Length header
        for you.




        ~$ curl -v 
        > -H 'Content-Type: application/json'
        > --data '{"a": 1, "b": 2}'
        > http://localhost:65451/cgi-bin/1.py

        * Trying ::1...
        * TCP_NODELAY set
        * Connection failed
        * connect to ::1 port 65451 failed: Connection refused
        * Trying 127.0.0.1...
        * TCP_NODELAY set
        * Connected to localhost (127.0.0.1) port 65451 (#0)
        > POST /cgi-bin/1.py HTTP/1.1
        > Host: localhost:65451
        > User-Agent: curl/7.58.0
        > Accept: */*
        > Content-Type: application/json
        > Content-Length: 16
        >
        * upload completely sent off: 16 out of 16 bytes

        === hung here for about 5 seconds ====

        < HTTP/1.1 504 Gateway Time-out
        < Date: Thu, 08 Mar 2018 17:53:30 GMT
        < Content-Type: text/html
        < Server: inets/6.4.5
        * no chunk, no close, no size. Assume close to signal end
        <
        * Closing connection 0






        share|improve this answer














        share|improve this answer



        share|improve this answer








        edited Mar 9 '18 at 15:10

























        answered Mar 9 '18 at 5:58









        7stud7stud

        29.1k96083




        29.1k96083






























            draft saved

            draft discarded




















































            Thanks for contributing an answer to Stack Overflow!


            • Please be sure to answer the question. Provide details and share your research!

            But avoid



            • Asking for help, clarification, or responding to other answers.

            • Making statements based on opinion; back them up with references or personal experience.


            To learn more, see our tips on writing great answers.




            draft saved


            draft discarded














            StackExchange.ready(
            function () {
            StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f10718572%2fpost-json-to-python-cgi%23new-answer', 'question_page');
            }
            );

            Post as a guest















            Required, but never shown





















































            Required, but never shown














            Required, but never shown












            Required, but never shown







            Required, but never shown

































            Required, but never shown














            Required, but never shown












            Required, but never shown







            Required, but never shown







            Popular posts from this blog

            MongoDB - Not Authorized To Execute Command

            How to fix TextFormField cause rebuild widget in Flutter

            Npm cannot find a required file even through it is in the searched directory