int treated as `self' in python3 - python

I want to build a simple server that dispatches requests depending on their path. So I wrote the following code:
from http.server import HTTPServer, BaseHTTPRequestHandler
import json
import socket
class Handler:
"""处理对应资源的请求"""
def __init__(self, dispatcher):
self.dispatcher = dispatcher
def handle(self):
"""根据dispatcher解析出来的path,调用对应的方法"""
command = 'do_' + self.dispatcher.command
print(command)
if not hasattr(self, command):
return;
method = getattr(self, command)
method(self)
def do_GET(self):
response = {
'message': 'message'
}
dispatcher.protocol_version = 'HTTP/1.1'
dispatcher.send_response(200, 'OK')
dispatcher.send_header('Content-type', 'text/plain')
dispatcher.wfile.write(bytes(json.dumps(response), 'utf-8'))
class dispatcher(BaseHTTPRequestHandler):
"""
根据url的不同分发请求
"""
def handle_one_request(self):
try:
self.raw_requestline = self.rfile.readline(65537)
if len(self.raw_requestline) > 65536:
self.requestline = ''
self.request_version = ''
self.command = ''
self.send_error(HTTPStatus.REQUEST_URI_TOO_LONG)
return
if not self.raw_requestline:
self.close_connection = True
return
if not self.parse_request():
# An error code has been sent, just exit
return
print(self.command)
print(self.path)
if self.path.startswith('/wrong'):
Handler(self).handle()
self.wfile.flush() #actually send the response if not already done.
except socket.timeout as e:
#a read or a write timed out. Discard this connection
self.log_error("Request timed out: %r", e)
self.close_connection = True
return
if __name__ == '__main__':
server = HTTPServer(('', 8080), dispatcher)
server.serve_forever()
The dispatcher will parse the incoming request and get the path so that it can decide which handler to call(though there is only one here for now).
In the handler class, it will call corresponding method based on the http method. In the do_GET method, it will call some methods in the dispatcher and that's where things go wrong.
When I ran this program and execute curl http://localhost:8080/wrong, I had the following exception:
GET
/wrong
do_GET
----------------------------------------
Exception happened during processing of request from ('127.0.0.1', 50072)
Traceback (most recent call last):
File "/usr/lib/python3.5/socketserver.py", line 313, in _handle_request_noblock
self.process_request(request, client_address)
File "/usr/lib/python3.5/socketserver.py", line 341, in process_request
self.finish_request(request, client_address)
File "/usr/lib/python3.5/socketserver.py", line 354, in finish_request
self.RequestHandlerClass(request, client_address, self)
File "/usr/lib/python3.5/socketserver.py", line 681, in __init__
self.handle()
File "/usr/lib/python3.5/http/server.py", line 422, in handle
self.handle_one_request()
File "hello.py", line 51, in handle_one_request
Handler(self).handle()
File "hello.py", line 18, in handle
method()
File "hello.py", line 25, in do_GET
dispatcher.send_response(200, 'OK')
File "/usr/lib/python3.5/http/server.py", line 487, in send_response
self.log_request(code)
AttributeError: 'int' object has no attribute 'log_request'
----------------------------------------
log_request is defined as follows in the super class of dispatcher:
def log_request(self, code='-', size='-'):
# blablabla
and it is called in dispatcher.send_response.
I guess the problem is that the 200 is treated as self by the interpreter.
If my guess is right, why is this happening?
If not, what causes this exception?
I know this question is still in the grammar level, but I'd appreciate it if someone can help me.

Related

basehttpserver does not respond to other requests

When I open my local server on Android (192.168.1.4) and on pc at the same time, pc never shows page (it is loading and loading and loading...) - this error raises when I kill my server:
Exception happened during processing of request from ('192.168.1.4', 54734)
Traceback (most recent call last):
File "/usr/lib/python2.7/SocketServer.py", line 295, in _handle_request_noblock
self.process_request(request, client_address)
File "/usr/lib/python2.7/SocketServer.py", line 321, in process_request
self.finish_request(request, client_address)
File "/usr/lib/python2.7/SocketServer.py", line 334, in finish_request
self.RequestHandlerClass(request, client_address, self)
File "/usr/lib/python2.7/SocketServer.py", line 655, in __init__
self.handle()
File "/usr/lib/python2.7/BaseHTTPServer.py", line 340, in handle
self.handle_one_request()
File "/usr/lib/python2.7/BaseHTTPServer.py", line 310, in handle_one_request
self.raw_requestline = self.rfile.readline(65537)
File "/usr/lib/python2.7/socket.py", line 476, in readline
data = self._sock.recv(self._rbufsize)
KeyboardInterrupt
my server script:
# !/usr/bin/env python
# -*- coding: utf-8 -*-
from BaseHTTPServer import BaseHTTPRequestHandler, HTTPServer
PORT = 20000
class S(BaseHTTPRequestHandler):
def log_message(self, format, *args):
return
def _set_headers(self):
self.send_response(200)
self.send_header('Content-type', 'text/html')
self.send_header('Access-Control-Allow-Origin', '*')
self.end_headers()
def do_GET(self):
self._set_headers()
if self.path == "/other":
self.wfile.write("other")
if self.path == "/something":
self.wfile.write('something')
def do_HEAD(self):
self._set_headers()
def do_POST(self):
self._set_headers()
self.wfile.write("hello post")
def run(server_class=HTTPServer, handler_class=S, port=PORT):
server_address = ('', port)
httpd = server_class(server_address, handler_class)
httpd.serve_forever()
if __name__ == "__main__":
from sys import argv
if len(argv) == 2:
run(port=int(argv[1]))
else:
run()
What is wrong with my code please?
I think your server works well: like any server, it runs indefinitely.
To see it working, just point your browser on the following URL: http://localhost:20000/something or http://127.0.0.1:20000/something.
You should get the text "something".
You should consider using Flask.
No idea, if this is correct approach but setting timeout helped:
...
def log_message(self, format, *args):
return
def setup(self):
BaseHTTPRequestHandler.setup(self)
self.request.settimeout(0.5)
...
https://pymotw.com/2/BaseHTTPServer/#threading-and-forking says:
HTTPServer is a simple subclass of SocketServer.TCPServer, and does not use multiple threads or processes to handle requests. To add threading or forking, create a new class using the appropriate mix-in from SocketServer.

Twisted: Mixing ReconnectingClientFactory with SSL write() raise ssl error frequently

I'm inheriting ReconnectingClientFactory and use SSL connection. We have it all running, but I am getting the following error after a few minute. Once this error happend, the connection is lost
Unhandled Error
Traceback (most recent call last):
File "/usr/local/hikvision/ezops/python/lib/python2.7/site-packages/twisted/python/log.py", line 103, in callWithLogger
return callWithContext({"system": lp}, func, *args, **kw)
File "/usr/local/hikvision/ezops/python/lib/python2.7/site-packages/twisted/python/log.py", line 86, in callWithContext
return context.call({ILogContext: newCtx}, func, *args, **kw)
File "/usr/local/hikvision/ezops/python/lib/python2.7/site-packages/twisted/python/context.py", line 118, in callWithContext
return self.currentContext().callWithContext(ctx, func, *args, **kw)
File "/usr/local/hikvision/ezops/python/lib/python2.7/site-packages/twisted/python/context.py", line 81, in callWithContext
return func(*args,**kw)
--- <exception caught here> ---
File "/usr/local/hikvision/ezops/python/lib/python2.7/site-packages/twisted/internet/posixbase.py", line 597, in _doReadOrWrite
why = selectable.doRead()
File "/usr/local/hikvision/ezops/python/lib/python2.7/site-packages/twisted/internet/tcp.py", line 208, in doRead
return self._dataReceived(data)
File "/usr/local/hikvision/ezops/python/lib/python2.7/site-packages/twisted/internet/tcp.py", line 214, in _dataReceived
rval = self.protocol.dataReceived(data)
File "/usr/local/hikvision/ezops/python/lib/python2.7/site-packages/twisted/protocols/tls.py", line 430, in dataReceived
self._flushReceiveBIO()
File "/usr/local/hikvision/ezops/python/lib/python2.7/site-packages/twisted/protocols/tls.py", line 400, in _flushReceiveBIO
self._flushSendBIO()
File "/usr/local/hikvision/ezops/python/lib/python2.7/site-packages/twisted/protocols/tls.py", line 352, in _flushSendBIO
bytes = self._tlsConnection.bio_read(2 ** 15)
File "/usr/local/hikvision/ezops/python/lib/python2.7/site-packages/OpenSSL/SSL.py", line 1384, in bio_read
self._handle_bio_errors(self._from_ssl, result)
File "/usr/local/hikvision/ezops/python/lib/python2.7/site-packages/OpenSSL/SSL.py", line 1365, in _handle_bio_errors
_raise_current_error()
File "/usr/local/hikvision/ezops/python/lib/python2.7/site-packages/OpenSSL/_util.py", line 48, in exception_from_error_queue
raise exception_type(errors)
OpenSSL.SSL.Error: []
my client code like this:
reactor.connectSSL(opscenter_addr, int(opscenter_port), NoahAgentFactory(), ssl.ClientContextFactory())
class NoahAgentFactory like this:
import logging
import traceback
from OpenSSL import SSL
from twisted.internet import reactor,ssl
from twisted.internet import task
from twisted.internet.protocol import Protocol
from twisted.internet.protocol import ReconnectingClientFactory
import DataPackageCodecFactory as Codec
from Header import MessageHandlerMap
from Handler import HBReq, DefaultRspHandler
from Util import Connection
logger = logging.getLogger('opsagent')
class NoahAgentProtocol(Protocol):
t = None
def connectionMade(self):
'''
客户端连接成功之后会自动调用该方法
:return:
'''
self.transport.setTcpKeepAlive(True) # maintain the TCP connection
self.transport.setTcpNoDelay(True) # allow Nagle algorithm
# 连接成功后保存连接信息
Connection.AgentTcpConnection = self
global t
logger.info('is already connect to the server')
self.recv_data_buffer = ''
# 创建定时的心跳任务,每隔30秒执行一次
t = task.LoopingCall(HBReq.execute, *[self])
t.start(30)
def dataReceived(self, data):
logger.debug("Received Message: %s", repr(data))
###code handler packages##########
def connectionLost(self, reason):
'''
当客户端连接断开的时候,会自动调用该方法
:param reason:
:return:
'''
try:
t.stop()
# 清空全局链接信息
Connection.AgentTcpConnection = None
except:
logger.error(traceback.format_exc())
logger.info('Connection is lost and Task stopped,Resaon =>%s', reason)
class NoahAgentFactory(ReconnectingClientFactory):
def startedConnecting(self, connector):
logger.info('Started to connect.')
def buildProtocol(self, addr):
logger.info('Connected.')
logger.info('Resetting reconnection delay')
self.resetDelay()
return NoahAgentProtocol()
def clientConnectionLost(self, connector, reason):
logger.info('Lost connection. Reason:%s', reason)
self.resetDelay()
self.retry(connector)
# ReconnectingClientFactory.clientConnectionLost(self, connector, reason)
def clientConnectionFailed(self, connector, reason):
logger.info('Connection failed. Reason:%s', reason)
self.resetDelay()
self.retry(connector)
I think it is not a bug in Twisted's TLS other than a mistake,I send the message not in the main reactor thread,as we know,twisted is single thread mode,so there is no need to consider thread safety issues.But I use reactor.callInThread to deal long time cost bussiness and send message directly,and the write() is not thread safety,so invoke that error,once I use reactor.callFromThread on send message,it's running right.

Error when transport.write() from thread in twisted

I'm trying to make this simple server script where multiple clients connect to it and are stored in the factory.connected_clients dictionary. I then want to show a menu so the user executing the server can select what client does he want to work with and what commands does he want to send them (like in a reverse shell). Here's the code:
class RshServer(protocol.Protocol):
def __init__(self, factory, addr):
self.addr = addr
self.factory = factory
def connectionMade(self):
address = self.addr.host + ':' + str(self.addr.port)
self.factory.connected_clients[address] = self
print '[*] Connection made with ' + address
class RshFactory(Factory):
def __init__(self):
self.connected_clients = {}
def buildProtocol(self, addr):
return RshServer(self, addr)
def show_server_menu():
print '1. Show connected clients'
print '2. Open client interface'
msg = raw_input('Select an option: ')
return msg
def show_client_menu():
print '1. Show all processes'
msg = raw_input('Select an option: ')
return msg
def server_interface():
while 1:
msg = show_server_menu()
command = server_commands.get(msg, None)
if command: command()
def client_interface():
protocol_name = raw_input('Enter client address: ')
protoc = rsh_factory.connected_clients.get(protocol_name, None)
if protoc:
msg = show_client_menu()
protoc.transport.write(msg)
rsh_factory = RshFactory()
server_commands = {
'1' : lambda: sys.stdout.write(str(rsh_factory.connected_clients)+'\n'),
'2' : client_interface
}
reactor.listenTCP(8000, rsh_factory)
reactor.callInThread(server_interface)
reactor.run()
However, when I select a client and execute the client interface function I get this error:
Unhandled Error
Traceback (most recent call last):
File "rsh_twisted_serv.py", line 58, in <module>
reactor.run()
File "/usr/lib/python2.7/dist-packages/twisted/internet/base.py", line 1192, in run
self.mainLoop()
File "/usr/lib/python2.7/dist-packages/twisted/internet/base.py", line 1204, in mainLoop
self.doIteration(t)
File "/usr/lib/python2.7/dist-packages/twisted/internet/epollreactor.py", line 396, in doPoll
log.callWithLogger(selectable, _drdw, selectable, fd, event)
--- <exception caught here> ---
File "/usr/lib/python2.7/dist-packages/twisted/python/log.py", line 88, in callWithLogger
return callWithContext({"system": lp}, func, *args, **kw)
File "/usr/lib/python2.7/dist-packages/twisted/python/log.py", line 73, in callWithContext
return context.call({ILogContext: newCtx}, func, *args, **kw)
File "/usr/lib/python2.7/dist-packages/twisted/python/context.py", line 118, in callWithContext
return self.currentContext().callWithContext(ctx, func, *args, **kw)
File "/usr/lib/python2.7/dist-packages/twisted/python/context.py", line 81, in callWithContext
return func(*args,**kw)
File "/usr/lib/python2.7/dist-packages/twisted/internet/posixbase.py", line 627, in _doReadOrWrite
self._disconnectSelectable(selectable, why, inRead)
File "/usr/lib/python2.7/dist-packages/twisted/internet/posixbase.py", line 257, in _disconnectSelectable
selectable.readConnectionLost(f)
File "/usr/lib/python2.7/dist-packages/twisted/internet/tcp.py", line 279, in readConnectionLost
self.connectionLost(reason)
File "/usr/lib/python2.7/dist-packages/twisted/internet/tcp.py", line 293, in connectionLost
abstract.FileDescriptor.connectionLost(self, reason)
File "/usr/lib/python2.7/dist-packages/twisted/internet/abstract.py", line 207, in connectionLost
self.stopWriting()
File "/usr/lib/python2.7/dist-packages/twisted/internet/abstract.py", line 429, in stopWriting
self.reactor.removeWriter(self)
File "/usr/lib/python2.7/dist-packages/twisted/internet/epollreactor.py", line 344, in removeWriter
EPOLLOUT, EPOLLIN)
File "/usr/lib/python2.7/dist-packages/twisted/internet/epollreactor.py", line 321, in _remove
self._poller.unregister(fd)
exceptions.IOError: [Errno 2] No such file or directory
I believe this is error is due to the transport.write() being called from a non-reactor thread. Am I right? How should I solve this?
SOLUTION: as #Glyph stated, the problem was indeed that I was calling transport.write() from a non-reactor thread (more details in his answer). I used the solution he proposed by changing protoc.transport.write() to reactor.callFromThread(lambda: protoc.transport.write(msg))
I think you mean "called from a non-reactor thread". No code in Twisted is thread-safe unless explicitly specified. See the threading documentation for more information. Use reactor.callFromThread to invoke Twisted methods from your stdio-reading thread, or use StandardIO to tell Twisted to read from standard input instead.

HTTP server hangs while accepting packets

I have written a simple http server to handle POST requests:
class MyHandler( BaseHTTPServer.BaseHTTPRequestHandler):
def do_POST( self ):
ctype, pdict = cgi.parse_header(self.headers.getheader('content-type'))
postvars = {}
try:
if ctype == 'application/x-www-form-urlencoded':
length = int(self.headers.getheader('content-length'))
postvars = cgi.parse_qs(self.rfile.read(length), keep_blank_values=1)
self.send_response( 200 )
self.send_header( "Content-type", "text")
self.send_header( "Content-length", str(len(body)) )
self.end_headers()
self.wfile.write(body)
except:
print "Error"
def httpd(handler_class=MyHandler, server_address = ('2.3.4.5', 80)):
try:
print "Server started"
srvr = BaseHTTPServer.HTTPServer(server_address, handler_class)
srvr.serve_forever() # serve_forever
except KeyboardInterrupt:
server.socket.close()
if __name__ == "__main__":
httpd( )
The server runs fine but sometimes it just hangs. When I press CTRL+C it gives the following error and then continues receiving data:
Exception happened during processing of request from ('1.1.1.2', 50928)
Traceback (most recent call last):
File "/usr/lib/python2.6/SocketServer.py", line 281, in _handle_request_noblock
self.process_request(request, client_address)
File "/usr/lib/python2.6/SocketServer.py", line 307, in process_request
self.finish_request(request, client_address)
File "/usr/lib/python2.6/SocketServer.py", line 320, in finish_request
self.RequestHandlerClass(request, client_address, self)
File "/usr/lib/python2.6/SocketServer.py", line 615, in __init__
self.handle()
File "/usr/lib/python2.6/BaseHTTPServer.py", line 329, in handle
self.handle_one_request()
File "/usr/lib/python2.6/BaseHTTPServer.py", line 312, in handle_one_request
self.raw_requestline = self.rfile.readline()
File "/usr/lib/python2.6/socket.py", line 406, in readline
data = self._sock.recv(self._rbufsize)
KeyboardInterrupt
Can someone tell me how to correct this? I can't make sense of the errors.
I completely rewrote my solution in order to fix two disadvantages:
It can treat timeout even if client has opened only a connection but did not start communicate.
If the client opens a connection, a new server process is forked. A slow client can not block other.
It is based on your code as most as possible. It is now a complete independent demo. If you open a browser on http://localhost:8000/ and write 'simulate error' to form and press submit, it simulates runtime error.
from http.server import HTTPServer, BaseHTTPRequestHandler
from socketserver import ForkingMixIn
from urllib.parse import parse_qs
class MyHandler(BaseHTTPRequestHandler):
def do_POST(self):
ctype, pdict = self.headers.get_params(header='content-type')[0]
postvars = {}
try:
if ctype == 'application/x-www-form-urlencoded':
length = int(self.headers['content-length'])
postvars = parse_qs(self.rfile.read(length), keep_blank_values=1
encoding='utf-8')
assert postvars.get('foo', '') != ['bar'] # can simulate error
body = 'Something\n'.encode('ascii')
self.send_response(200)
self.send_header("Content-type", "text")
self.send_header("Content-length", str(len(body)))
self.end_headers()
self.wfile.write(body)
except Exception:
self.send_error(500)
raise
def do_GET(self):
# demo for testing POST by web browser - without valid html
body = ('Something\n<form method="post" action="http://%s:%d/">\n'
'<input name="foo" type="text"><input type="submit"></form>\n'
% self.server.server_address).encode('ascii')
self.send_response(200)
self.send_header("Content-type", "text/html")
self.send_header("Content-length", str(len(body)))
self.end_headers()
self.wfile.write(body)
class ForkingHTTPServer(ForkingMixIn, HTTPServer):
def finish_request(self, request, client_address):
request.settimeout(30)
# "super" can not be used because BaseServer is not created from object
HTTPServer.finish_request(self, request, client_address)
def httpd(handler_class=MyHandler, server_address=('localhost', 8000)):
try:
print("Server started")
srvr = ForkingHTTPServer(server_address, handler_class)
srvr.serve_forever() # serve_forever
except KeyboardInterrupt:
srvr.socket.close()
if __name__ == "__main__":
httpd()
Forking can be disabled for e.g. debugging purposes by removing class SocketServer.ForkingMixIn from code.
EDIT Updated for Python 3, but a warning from Python 3 docs should be noted:
Warning: http.server is not recommended for production. It only implements basic security checks.

Callback chain with independent data, not related to the chain

I am trying to perform a simple callback sequence in twisted. The idea is that I login to a service, and when the login has succeeded, I start sending commands. This is my code:
from twisted.internet import reactor, defer
class MyService:
def __init__ (self):
self.handle = None
def login(self):
def onConnect(handle):
self.handle = handle
return
df = defer.Deferred().addCallback(onConnect)
reactor.callLater(2, df.callback, "dummyhandle")
return df
def sendCommand(self, command):
def onResult(result):
print result
return result
if self.handle == None:
print "Not logged in"
return
else:
df = defer.Deferred().addCallback(onResult, result ="xxx")
return df
my = MyService ()
my.login().addCallback(my.sendCommand, command = "format")
reactor.run()
Running that code produces the following stacktrace:
Unhandled error in Deferred: Traceback (most recent call last): File "/usr/lib/python2.6/dist-packages/twisted/internet/base.py", line 1179, in mainLoop
self.runUntilCurrent() File "/usr/lib/python2.6/dist-packages/twisted/internet/base.py", line 778, in runUntilCurrent
call.func(*call.args, **call.kw) File "/usr/lib/python2.6/dist-packages/twisted/internet/defer.py", line 280, in callback
self._startRunCallbacks(result) File "/usr/lib/python2.6/dist-packages/twisted/internet/defer.py", line 354, in _startRunCallbacks
self._runCallbacks()
--- <exception caught here> --- File "/usr/lib/python2.6/dist-packages/twisted/internet/defer.py", line 371, in _runCallbacks
self.result = callback(self.result, *args, **kw) exceptions.TypeError: sendCommand() got multiple values for keyword argument 'command'
The important thing here is that sendCommand does not need the result of the login, but different data. It needs that login has completed (that is why I want it in the callback chain), but it is not interested on the result of the login (as long as it is not an error, which will be handled in the error chain anyway).
What am I doing wrong here?
Easy, the handler must have result as its first argument:
def sendCommand(self, in_result, command):
do_the_stuff

Categories

Resources