Android HttpPost not working with python CGI server - python

I'm buliding an android app and need to submit data to my python CGI server. I'm usually pulling data off the server with HttpGet and all those calls work correctly and quickly. When I try to push data with HttpPost, the program hangs indefinitely until I long press the return button on the emulator and force quit the program. The CGI server seems to start the script but doesn't return until I force quit the android app. When the CGI script returns, it says CGI script exited OK but it hasn't done anything.
At the moment I'm executing the request in the UI thread. I know it should be done in an AsyncTask but I want a solution before a try a good solution.
I've spent 3 days trying different things and looking at forums with no luck. I'd really appreciate suggestions. Here's the relevant part of my Android code:
private final String serverIP = "10.0.2.2";
HttpClient httpclient = new DefaultHttpClient();
HttpParams params = httpclient.getParams();
HttpConnectionParams.setConnectionTimeout(params, 5000);
HttpConnectionParams.setSoTimeout(params, 5000);
String URI = "http://"+serverIP+":8000/cgi-bin/test.py?order_submit=0";
HttpPost post = new HttpPost(URI);
List<NameValuePair> kvPairs = new ArrayList<NameValuePair>(2);
kvPairs.add(new BasicNameValuePair("name", "bob"));
kvPairs.add(new BasicNameValuePair("surname", "the builder"));
try {
Log.i(TAG, "Trying to set Entity");
post.setEntity(new UrlEncodedFormEntity(kvPairs, HTTP.UTF_8));
Log.i(TAG, "Trying to Post");
HttpResponse response = httpclient.execute(post);
Log.i(TAG, "execute done");
httpclient.getConnectionManager().closeExpiredConnections();
} catch (ClientProtocolException e) {
Log.e(TAG,e.toString());
} catch (UnsupportedEncodingException e) {
Log.e(TAG,e.toString());
} catch (IOException e) {
Log.e(TAG,e.toString());
}
which outputs the following in LogCat:
INFO/App:(534): Trying to set Entity
INFO/App:(534): Trying to Post
ERROR/App:(534): java.net.SocketTimeoutException: The operation timed out
My Python CGI server script is as follows:
import os, sys, cgi, csv
import cgitb #CGI error backtracer
cgitb.enable()
form = cgi.FieldStorage()
if "order_submit" in form:
ofile = open(os.getcwd() + "/Forms/Output/foo.csv", "wb")
writer = csv.writer(ofile, delimiter=',', quotechar='"',quoting=csv.QUOTE_ALL)
writer.writerow(["Name", form["name"].value])
writer.writerow(["Surname", form["surname"].value])
ofile.close()
After the Android app request has timed out, foo.csv still does not exist. The same is true even if the if part of the script contains the following, and doesn't use the CGI form at all:
if "order_submit" in form:
ofile = open(os.getcwd() + "/Forms/Output/foo.csv", "wb")
writer = csv.writer(ofile, delimiter=',', quotechar='"',quoting=csv.QUOTE_ALL)
writer.writerow(["Name", "harry"])
ofile.close()
After the httpclient.execute(post); , this is the order of events:
App: httpclient.execute(post);
CGI server: POST /cgi-bin/test.py?order_submit=0 HTTP/1.1" 200
CGI server: starts the 2nd python script
a few second's waiting...
App: java.net.SocketTimeoutException: The operation timed out
Python Script: creates the correct dummy file
CGI server: CGI script exited OK

The error sounds like the given IP is not reachable or port 8000 is blocked by the ISP or firewalled.

I changed
HttpClient httpclient = new DefaultHttpClient();
HttpParams params = httpclient.getParams();
HttpConnectionParams.setConnectionTimeout(params, 5000);
HttpConnectionParams.setSoTimeout(params, 5000);
to
HttpParams params = new BasicHttpParams();
HttpConnectionParams.setConnectionTimeout(params, timeout);
HttpConnectionParams.setSoTimeout(params, timeout);
HttpClient httpclient = new DefaultHttpClient(params);
and it works fine now. I don't think I changed anything else. The BasicHttpParams must initialise something that the DefaultHttpClient doesn't, which is strange because the way I've been doing it works fine for HttpGet.

Related

Shutting down Flask application from C#?

I am relaying HTTP requests from a C# application by sending JSON data to a localhost flask application, sending the requests with python, and relaying the response back to my C# application. Needs to be done this way because the server I am dealing with is 3rd party and fingerprints SCHANNEL requests and sends back dummy data (Does this with Powershell as well, but not curl, Postman, or Python).
var process = new Process();
process.StartInfo = new ProcessStartInfo()
{
FileName = "cmd.exe",
Arguments = #" /k python Assets\Scripts\server.py",
UseShellExecute = true
};
process.Start();
I found this solution, which uses an endpoint (/shutdown)
def shutdown_server():
func = request.environ.get('werkzeug.server.shutdown')
if func is None:
raise RuntimeError('Not running with the Werkzeug Server')
func()
Get a warning that it is being deprecated. I can live with that, but my OCD makes me want to do this properly. The warning tells me this is a hacky solution.
I am new to python/flask. What would be a good way about going about this?
Sidenote: process.Kill() doesn't work. Wish it did.
process.CloseMainWindow() seems to do the trick from my initial tests. Why process.Close() or process.Kill() do not work, is beyond me.

bottle.py stalls when client disconnects

I have a python server written with bottle. When I access the server from a website using Ajax, and then close the website before the server can send its response, the server gets stuck trying to send the response to a destination that no longer exists. When this happens, the server becomes unresponsive to any requests for about 10 seconds, before resuming normal operations.
How can I prevent this? I would like bottle to immediately stop trying if the website that made the request no longer exists.
I start the server like this:
bottle.run(host='localhost', port=port_to_listen_to, quiet=True)
and the only url exposed by the server is this:
#bottle.route('/', method='POST')
def main_server_input():
request_data = bottle.request.forms['request_data']
request_data = json.loads(request_data)
try:
response_data = process_message_from_scenario(request_data)
except:
error_message = utilities.get_error_message_details()
error_message = "Exception during processing of command:\n%s" % (error_message,)
print(error_message)
response_data = {
'success' : False,
'error_message' : error_message,
}
return(json.dumps(response_data))
Is process_message_from_scenario a long-running function? (Say, 10 seconds?)
If so, your one-and-only server thread will be tied up in that function, and no subsequent requests will be serviced during that time. Have you tried running a concurrent server, like gevent? Try this:
bottle.run(host='localhost', port=port_to_listen_to, quiet=True, server='gevent')

I need to host node js through python

var util = require('util');
var exec = require('child_process').spawn;
var run = exec('/usr/bin/python', ['-m', 'SimpleHTTPServer', '9002']);
run.stdout.on('data', function(data){
console.log('stdout: ' + data.toString());
});
run.stderr.on('data', function (data) {
console.log('stderr: ' + data.toString());
});
test.py
from bottle import route, run, template
#route('/hello/<name>')
def index(name):
return template('<b>Hello {{name}}</b>!', name=name)
run(host='localhost', port=9002)
I am new to node js and python just i want do communicate between node js to python with localhost. A simple python script with localhost url to hit node js url after running node js scrpit whih call python script in node and host the same on web browser.
Not entirely sure I see the problem. Your code works.
1) Make sure you access localhost:9002
2) If you meant to run your bottle code, then use
var run = exec('/usr/bin/python', ['/path/to/bottle_server.py']);
As for communicating back and forth between the Python code and the Node.js code, then you need sockets. Some libraries to look at could include socket.io or use a messaging queue like zmq.
If you want one-way communication to your python API, then you need to perform HTTP requests to http://localhost:9002 from the Node code. Alternatively, Node is very much capable of the same functionality you've included in the Python code on its own.
EDIT
Regarding below comments, here is an updated script. You need to inherit the parent's stdout and stderr, otherwise, as you see in the image above, it thinks python is printing to stderr
var util = require('util');
const spawn = require('child_process').spawn;
var run = spawn('/usr/bin/python', ['-m', 'SimpleHTTPServer', '9002'],
{ stdio: ['ignore', 'inherit', 'inherit' ] });
run.on('exit', (code) => {
console.log(`Child exited with code ${code}`);
});

How to handle multiple clients asynchronously , on a web socket using python?

I'm basically building a visual trace route application. The trace route is basically done using a python code and the results are send to the HTML page in real time using web socket. I basically need to do long polling( the server receives one request, process it and sent a maximum of 30 replies to each client at regular or irregular intervals), as well as handle multiple clients. I basically manipulated the below code to work for my application. I found the code from Asynchronous Bottle Framework
from bottle import request, Bottle, abort
app = Bottle()
#app.route('/websocket')
def handle_websocket():
wsock = request.environ.get('wsgi.websocket')
if not wsock:
abort(400, 'Expected WebSocket request.')
while True:
try:
message = wsock.receive()
wsock.send("Your message was: %r" % message)
except WebSocketError:
break
from gevent.pywsgi import WSGIServer
from geventwebsocket import WebSocketHandler, WebSocketError
server = WSGIServer(("0.0.0.0", 8080), app,
handler_class=WebSocketHandler)
server.serve_forever()
It does work on a single request. When I issue the second one.. 'wsock.send()' fails... it shows socket dead error. Could someone guide me on, how to handle multiple clients as well. Like, should I spawn a different process for each client ? What if a client requests trace for one domain, and again(before the full result is provided to him) requests for another. Thanks in advice
Client side code :
<script type="text/javascript">
var ws = new WebSocket("ws://example.com:8080/websocket");
ws.onopen = function() {
ws.send("Hello, world");
};
ws.onmessage = function (evt) {
alert(evt.data);
};

How can I call a specific function/method in a Python script from Javascript(jquery/ajax)

To clarify:
I am running this as cgi via Apache web server. That isn't the problem
My question is regarding a way to specify which function within the Python script to run when I call it via an ajax request.
I read a tutorial that said to pass the function name I want to call as a var. I did that.
In the Python, I tried
Here's my ajax function
$(document).ready(function() {
$.ajax({
url: "monStat.py",
type: "post",
data: {'callFunc':'isRunning'},
success: function(response){
$('#blurg').html(response).fadeIn(1500);
}
});
});
Here's the Python
def main():
if callFunc:
funcResp = isRunning()
else:
print("No function passed")
def isRunning( process_name ):
''' the content '''
You'll need to make your script web-capable. I haven't worked with CGI, so here's an example with Flask:
from flask import Flask, request
app = Flask(__name__)
#app.route('/is_running', methods=['POST'])
def isRunning():
process_name = request.values.get('name', None)
''' the content '''
if __name__ == '__main__':
app.run(host='127.0.0.1', port=5000)
Now, you can just send a request to /is_running:
$.ajax({
url: "/is_running",
type: "post",
data: {'name': 'ls'},
success: function(response){
$('#blurg').html(response).fadeIn(1500);
}
});
Even though you don't mention what kind of web framework you are using (if any), I am going to assume from the naming of your url that you are trying to directly call a python script on your server.
The only way for this to work is if your monStat.py script is structured as a CGI script, and hosted on your server accordingly (in a way that CGI scripts will be executed). Your javascript implies that you want to make a POST request to this script, so your python script will need to accept a POST request, and then read the parameters and act on them. You cannot just name a callable as a string in javascript and have the CGI script automatically know what to run. This is the place of a web framework to provide advanced URL handling.
If you are trying to just call a regular python script via a url, that is not going to work. The most basic primitive approach is using the python CGI module. This is good for just learning and getting started, but a very inefficient and dated approach. You should probably look into a web framework: Python WebFrameworks
Update
As you stated you are in fact using a CGI script...
"Routing" is something you get for free when you use web frameworks. It takes the incoming request into the main loop and decides where it should go to be handled. When you use only CGI, you will have to do this yourself. Every time you make a request to the CGI script, it executes just like a normal script, with a normal entrypoint.
In that entrypoint, you have to read the request. If the request is POST and contains "is_running" then you can forward that request off to your is_running() handler. The "function name" is just string data. It is up to your code to read the request and determine what to do.
Here is a super rough example of what it might look like, where you map some acceptable handlers to functions you allow:
#!/usr/bin/env python
import cgi
import cgitb
cgitb.enable()
def isRunning(form):
print "Content-Type: text/html\n"
print "isRunning()"
print form.getvalue('name')
def _error(*args):
print "Content-Type: text/html\n"
print "Error"
HANDLERS = {
'isRunning': isRunning
}
def main():
form = cgi.FieldStorage()
h_name = form.getvalue('callFunc')
handler = HANDLERS.get(h_name, _error)
handler(form)
if __name__ == "__main__":
main()
This is a start:
import cgi
fs = cgi.FieldStorage()
print "Content-type: text/plain\n"
for key in fs.keys():
print "%s = %s" % (key, fs[key].value)

Categories