Read JSON data with python cgi [duplicate] - android

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);

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/json\n\n'
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.

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

Adding a little bit to the great #7stud's answer
I had some problems with content length when reading unicode which I fixed by reading from buffer:
content_length = int(os.environ["CONTENT_LENGTH"])
data = sys.stdin.buffer.read(content_length).decode('utf-8')

Related

Speech to text api - use morethen 1min audio using rest api show error

When i select audio morethen 30sec or 1min then its show below error
--> Sync input too long. For audio longer than 1 min use LongRunningRecognize with a 'uri' parameter.
-> https://speech.googleapis.com/v1p1beta1/speech:recognize?key="api key"
body -> {
"audio":{"content":" // base64 formated audio // "},
"config":{
"enableAutomaticPunctuation":true,
"encoding":"WEBM_OPUS",
"sampleRateHertz": 16000,
"languageCode":"en-US",
"model":"default"
}
}
You should use speech:longrunningrecognize endpoint for audio longer than 1 minute.
The endpoint with key is https://speech.googleapis.com/v1/speech:longrunningrecognize?key="api_key"
Using curl I can send a request to this endpoint:
curl -s -H "Content-Type: application/json" \
https://speech.googleapis.com/v1/speech:longrunningrecognize?key=AIzaSyD....\
-d "{
'config': {
'language_code': 'en-US'
},
'audio':{
'uri':'gs://cloud-samples-tests/speech/brooklyn.flac'
}
}"
Output:
{
"name": "1521059426290567438"
}
When a request is sent to the endpoint, it will create a long running operation and it will return a name. This will be used to check the status of the long running operation. You can check the status by sending a request to this endpoint https://speech.googleapis.com/v1/operations/<name>. If the operation is done, it will return the transcript in the response.
Check status:
curl -H "Content-Type: application/json; charset=utf-8" \
"https://speech.googleapis.com/v1/operations/1521059426290567438?key=AIzaSyD...."
Output:

Sending HTTP GET request using FUEL, nothing comes thru

I'm trying to send a simple GET request using FUEL to my webserver, when I try to debug, I can see what happens when I click the button in the app, then I get this output:
I/DpmTcmClient: RegisterTcmMonitor from: $Proxy1
I/System.out: --> GET http://1.1.1.1/post.php
Body : (empty)
Headers : (0)
I/System.out: <-- -1 http://1.1.1.1/post.php
Response :
Length : 0
I/System.out: Body : (empty)
Headers : (0)
I've changed the IP to a random open one, using my real IP in the script.
This is my script (which is taken from github)
uttonClickMe.setOnClickListener{
Fuel.get("http://1.1.1.1/post.php")
.response { request, response, result ->
println(request)
println(response)
val (bytes, error) = result
if (bytes != null) {
println("[response bytes] ${String(bytes)}")
}
}
}
However I see nothing on my servers end in the logs about requests coming thru, can someone point me in the right direction?
I figured it out, even thru I tried with and without ssl, it was with an invalid ssl cert, it is now working with domain and valid ssl.

Android Retrofit + Rxjava: How to get response on non200 code?

This is how my request looks like:
ApiService apiService = retrofit.create(ApiService.class);
Observable<Response<UserUpdateResponse>> response = apiService.updateUser(Utils.getHeader(), object);
response.subscribeOn(Schedulers.newThread())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(this::onSuccessUpdate,
this::onErr,
this::hideDialogLoading);
It's supposed to return 'code':'205' 'msg':'successfully update'. But when server response any code 201,202 (anything not 200) it will go to error.
Here is the Error.
java.net.ProtocolException: HTTP 205 had non-zero Content-Length: 121
So how do I prevent it from error, or how do I get error body? Thank you!.
HTTP response codes have a predefined definition and some have requirements that they must fullfill to be considered a valid HTTP payload. You cannot redefine what these codes mean for your application and expect well-implemented clients to accept it.
Looking specifically at HTTP 205 - Reset Content, which has the following requirement:
Since the 205 status code implies that no additional content will be provided, a server MUST NOT generate a payload in a 205 response.
Generally applications will just return HTTP 200 for all requests and include application-specific error codes in the payload. What you're doing does not make much sense.
So technically, I can get response 2xx. The problem was that server response body in response code 205 that suppose to be null (https://www.rfc-editor.org/rfc/rfc7231#section-6.3.6). So after set body null on server, android side works fine.

Spring MVC download PDF on chrome issue

I have two services to generate and download PDF files. First there is POST (for hiding data) which save data in session, generate unique id and return it.
Second service is GET (param is unique id from POST) which remove id from session, generate PDF and returns it as stream. It looks like:
#RequestMapping(value = "/get", method = RequestMethod.GET)
#ResponseBody
public HttpEntity<byte[]> getData(
#ApiParam(name="hash", value="hash", required=true)
#RequestParam(value="hash", required = true) String hash,
#Context HttpServletResponse response) throws IOException {
Map reportData = reportsContext.getReportData(hash);
/*generate PDF here*/
return new HttpEntity<>(report.getContent(), getHeaders(report));
}
and getHeaders() is:
private HttpHeaders getHeaders(ReportData report) {
HttpHeaders headers = new HttpHeaders();
headers.setContentType(MediaType.valueOf("application/pdf"));
headers.add("Content-Disposition", "attachment; filename=".concat(report.getTitle()).concat(".pdf"));
return headers;
}
It generally works fine on all browsers and systems but Android Chrome. First, I found out that Chrome on Android send two GETs (one from browser, second from download manager) - because hash was deleted, second GET thowed exception. Next step was saving generated stream in session (>.<) and returned it on second GET - despite returned streams was the same (when returning from getData()), second response is bad formated. I guess this is some kind of Spring issue, somehow it changes formatting.
There are initials of responses:
first GET:
HTTP/1.1 200 OK X-Powered-By: Express server: Apache-Coyote/1.1
content-disposition: attachment;
filename=operation_20052016.pdf content-type:
application/pdf content-length: 28626 date: Fri, 20 May 2016 07:51:08
GMT connection: close
%PDF-1.4 %âăĎÓ
second GET:
HTTP/1.1 200 OK X-Powered-By: Express server: Apache-Coyote/1.1
content-disposition: attachment;
filename=operation_20052016.pdf content-type:
application/pdf transfer-encoding: chunked date: Fri, 20 May 2016
07:51:13 GMT connection: close
2000 "JVBERi0xLjQKJeLj
------------ANSWER------------
Finally I put manually producible attribute, like:
request.setAttribute(HandlerMapping.PRODUCIBLE_MEDIA_TYPES_ATTRIBUTE, Sets.newHashSet(MediaType.valueOf("application/pdf")));
just before returning correct PDF. In case of error I dont set produces attribute so it take default value.
ANSWER:
Finally I put manually producible attribute, like:
request.setAttribute(HandlerMapping.PRODUCIBLE_MEDIA_TYPES_ATTRIBUTE, Sets.newHashSet(MediaType.valueOf("application/pdf")));
just before returning correct PDF. In case of error I dont set produces attribute so it take default value.

Handling JSON on server-side

I want to send data from my Android app to my server.
On the client-side, meaning the application,I can create the JSON object and send it to the server.
The problem is, I don't know how to 'handle' it on the server side.All I want my server to do is to receive the JSON, parse it, and show it to me.That's it.
I know it's pretty vague question, but I don't really know where to start here, and would love if anyone could show me a complete tutorial.
Thanks!
Use PHP and json_decode()
http://php.net/manual/en/function.json-decode.php
Here a quick example how to handle the data:
// get json
$input = json_decode($_GET["json"]);
// get values
$firstname = $input->firstName;
$surename = $input->lastName;
$age = intval($input->age);
// check values
if (isset($firstname) && !empty($firstname) &&
isset($surename) && !empty($surename) &&
isset($age) && is_numeric($age))
{
// do something
echo "Hello ".htmlspecialchars($firstname)." ".htmlspecialchars($surename)."!<br>";
echo "You are $age years old! Wow.";
}
else
{
echo "Some values are missing or incorrect";
}
I used the GET parameter in this example. If you have larger data, use POST instead of GET.
Example:
URL: http://localhost/test/index.php?json={ "firstName" : "John","lastName" : "Doe","age" : 23 }
Output: Hello John Doe!
You are 23 years old! Wow.
But: Make sure you encode the JSON data at your application. In my example the browser does it.
// Some groovy code to dump an incoming request
import com.sun.net.httpserver.*;
HttpServer server = HttpServer.create(new InetSocketAddress(2228),0)
server.createContext('/', { HttpExchange exchange ->
println 'got a request'
println 'requestHeaders '+exchange.requestHeaders
println 'requestBody '+exchange.requestBody.text
exchange.sendResponseHeaders(200,0);
exchange.responseBody.write('hello from groovy land.'.bytes)
exchange.responseBody.close();
println 'all done'
} as HttpHandler)
server.start();
You can even use some shell script CGI file on the server. Here's a sample returning some fixed data to a JSONP request for testing something.
#!/bin/bash
#
# Handle a JSONP request for data returning a fake queue status result.
read -r -d '' DATA <<'EOF'
{
name: "TESTHOST",
status: "running",
items: [
{id:"4",status:"failed",title:"anadin map 2",user:"pat",progress:100},
{id:"2",status:"running",title:"silicon map",user:"tim",progress:52},
{id:"3",status:"queued",title:"anadin map",user:"pat",progress:0},
{id:"6",status:"queued",title:"neon calibration",user:"ian",progress:0}
]
}
EOF
CB=$(echo $QUERY_STRING | sed -n 's/.*jsoncallback=\([^&]*\).*$/\1/p')
DATA=${DATA/52/$(expr $RANDOM % 100)}
DATA="${CB}(${DATA});"
echo -e "content-type: application/json\r"
echo -e "content-length: ${#DATA}\r"
echo -e "x-test: $CB\r"
echo -e "\r"
echo "$DATA"
Substitute some parsing of the request data and return as appropriate.

Categories

Resources