Python MJPEG stream don't work outside VLC - python

I'm creating a streaming mjpeg from some IP cameras,the streaming with VLC works perfectly, just do not work inside a web page and other enterprise devices where other MJPEG streams taken from the internet work perfectly
here is my code:
class Streamer(Thread):
def __init__(self, *args, **kwargs):
self.container = kwargs.pop("container", None)
# self.q = kwargs.pop("queue", None)
# self.stream = kwargs.pop("stream", None)
super(Streamer, self).__init__(*args, **kwargs)
def run(self):
try:
print("dichiarazione handler")
server = ThreadedHTTPServer(('192.168.1.182', 8080), HandlerArguments(self.container))
print('started httpserver...')
server.serve_forever()
except KeyboardInterrupt:
print('^C received, shutting down server')
server.socket.close()
def HandlerArguments(init_args):
class MyHandler(BaseHTTPRequestHandler):
def __init__(self, *args, **kwargs):
self.container = init_args
super(MyHandler, self).__init__(*args, **kwargs)
def do_GET(self):
print("GET")
if self.path.endswith('.mjpeg'):
self.container.stream = True
self.send_response(200)
self.send_header('Pragma:', 'no-cache')
self.send_header('Cache-Control:', 'no-cache')
self.send_header('Content-type:', 'multipart/x-mixed-replace;boundary=--myboundary')
self.end_headers()
try:
while self.container.stream == True:
# print(self.queue.qsize())
print("ciclo")
img = self.container.finalq.get()
ret, img_jpg = cv2.imencode(".jpeg", img, (cv2.IMWRITE_JPEG_QUALITY, 90))
self.wfile.write('--myboundary'.encode('utf-8'))
self.send_header('Content-type:','image/jpeg')
# self.send_header('Content-length:', str(len(img_jpg)))
self.end_headers()
img_str = img_jpg.tostring()
self.wfile.write(img_str)
# self.wfile.write('--myboundary\r\n'.encode('utf-8'))
# self.send_response(200)
# time.sleep(0.05)
except:
self.container.stream = False
while not self.container.finalq.empty():
self.container.finalq.get()
elif self.path.endswith('.jpg'):
self.send_response(200)
self.send_header('Pragma:', 'no-cache')
self.send_header('Cache-Control:', 'no-cache')
self.send_header('Content-type:','image/jpeg')
self.end_headers()
img = self.container.finalq.get()
ret, img_jpg = cv2.imencode(".jpeg", img, (cv2.IMWRITE_JPEG_QUALITY, 90))
# self.send_header('Content-length:', str(len(img_jpg)))
img_str = img_jpg.tostring()
self.wfile.write(img_str)
return MyHandler
class ThreadedHTTPServer(ThreadingMixIn, HTTPServer):
#class ThreadedHTTPServer(HTTPServer):
"""Handle requests in a separate thread."""
I think the problem is in the request header, in particular this is a stream taken from the internet compared with my stream
curl -I http://85.90.40.19/mjpg/video.mjpg
HTTP/1.0 200 OK
Cache-Control: no-cache
Pragma: no-cache
Expires: Thu, 01 Dec 1994 16:00:00 GMT
Connection: close
Content-Type: multipart/x-mixed-replace; boundary=--myboundary
///////
curl -I http://192.168.1.182:8080/stream.mjpeg
HTTP/1.0 501 Unsupported method ('HEAD')
Server: BaseHTTP/0.6 Python/3.4.0
Date: Mon, 20 Jul 2015 10:00:54 GMT
Content-Type: text/html;charset=utf-8
Connection: close
Content-Length: 474
Especially in my request i see:
Content-Type: text/html;charset=utf-8
while in my code i run
self.send_header('Content-type:','image/jpeg')
Thanks in advance guys :)

curl -I sends a HTTP HEAD request.
In your code you're handling only the HTTP GET requests:
def do_GET(self):
See the error message: HTTP/1.0 501 Unsupported method ('HEAD')
Handle HEAD requests too:
def do_HEAD(self):
and output the expected headers since the clients may issue a HEAD before a GET.

Related

PJSUA2 python swig module

I'm trying to write a simple SIP agent to receive a call using PJSUA2 python swig module, but can't see how this swig module works. I've got the following code
import pjsua2 as pj
import time
class Endpoint(pj.Endpoint):
"""
This is high level Python object inherited from pj.Endpoint
"""
instance = None
def __init__(self):
pj.Endpoint.__init__(self)
Endpoint.instance = self
def validateUri(uri):
return Endpoint.instance.utilVerifyUri(uri) == pj.PJ_SUCCESS
def validateSipUri(uri):
return Endpoint.instance.utilVerifySipUri(uri) == pj.PJ_SUCCESS
# Call class
class Call(pj.Call):
"""
High level Python Call object, derived from pjsua2's Call object.
"""
def __init__(self, acc, peer_uri='', call_id=pj.PJSUA_INVALID_ID):
pj.Call.__init__(self, acc, call_id)
self.acc = acc
self.peerUri = peer_uri
self.connected = False
self.onhold = False
def onCallState(self, prm):
ci = self.getInfo()
self.connected = ci.state == pj.PJSIP_INV_STATE_CONFIRMED
def onCallMediaState(self, prm):
ci = self.getInfo()
for mi in ci.media:
if mi.type == pj.PJMEDIA_TYPE_AUDIO and \
(mi.status == pj.PJSUA_CALL_MEDIA_ACTIVE or
mi.status == pj.PJSUA_CALL_MEDIA_REMOTE_HOLD):
m = self.getMedia(mi.index)
am = pj.AudioMedia.typecastFromMedia(m)
# connect ports
Endpoint.instance.audDevManager().getCaptureDevMedia().startTransmit(am)
am.startTransmit(Endpoint.instance.audDevManager().getPlaybackDevMedia())
if mi.status == pj.PJSUA_CALL_MEDIA_REMOTE_HOLD and not self.onhold:
print("'%s' sets call onhold" % self.peerUri)
self.onhold = True
elif mi.status == pj.PJSUA_CALL_MEDIA_ACTIVE and self.onhold:
print("'%s' sets call active" % self.peerUri)
self.onhold = False
def onDtmfDigit(self, prm):
# print("Got DTMF:" + prm.digit)
pass
def onCallMediaTransportState(self, prm):
# print("Media transport state")
pass
class Account(pj.Account):
def onRegState(self, prm):
print("***OnRegState: " + prm.reason)
def onMwiInfo(self, prm):
print("OnMwiState: " + prm.reason)
def onBuddyState(self, prm):
print("OnBuddyState: " + prm.reason)
def onIncommingSubscribe(self, prm):
print("OnSubscribeState: " + prm.reason)
def OnIncomingCall(self, prm):
c = Call(self, call_id=prm.callId)
call_prm = pj.CallOpParam()
call_prm.statusCode = 180
c.answer(call_prm)
ci = c.getInfo()
if input(f"Accept call from {ci.remoteUri}?") == u'yes':
call_prm.statusCode = 200
c.answer(call_prm)
else:
c.hangup(call_prm)
def initalise_sip_stack():
ep_cfg = pj.EpConfig()
ep = Endpoint()
ep.libCreate()
ep.libInit(ep_cfg)
sip_tp_config = pj.TransportConfig()
sip_tp_config.port = 5060
ep.transportCreate(pj.PJSIP_TRANSPORT_UDP, sip_tp_config)
ep.libStart()
acfg = pj.AccountConfig()
acfg.idUri = "sip:056004#172.20.1.8"
acfg.regConfig.registrarUri = "sip:172.20.1.8"
creds = pj.AuthCredInfo("digest", "*", "056004", 0, "somepass")
acfg.sipConfig.authCreds.append(creds)
acc = Account()
acc.create(acfg)
return ep
if __name__ == "__main__":
endpoint = initalise_sip_stack()
time.sleep(600)
endpoint.libDestroy()
This little client is able to register in my asterisk server as you can see
raspberrypi*CLI> pjsip show contacts
Contact: <Aor/ContactUri..............................> <Hash....> <Status> <RTT(ms)..>
==========================================================================================
Contact: 056003/sip:056003#172.20.1.13:5060 058bca1427 Avail 41.057
Contact: 056004/sip:056004#172.20.1.2:5060;ob e8ff0c4e2b Avail 2.358
Objects found: 2
However, when I place a call from 056003 contact, I can see the following trace from pjsua2:
16:52:37.918 pjsua_core.c .RX 947 bytes Request msg INVITE/cseq=23923 (rdata0x7f5f6c001c48) from UDP 172.20.1.8:5060:
INVITE sip:056004#172.20.1.2:5060;ob SIP/2.0
Via: SIP/2.0/UDP 0.0.0.0:5060;rport;branch=z9hG4bKPjada6202d-813b-499c-9b5c-2ad5abf6706e
From: "MI 3" <sip:056003#172.20.1.8>;tag=91efaf53-e6fb-45dc-b2d4-ddc99a6c3c36
To: <sip:056004#172.20.1.2;ob>
Contact: <sip:056003#0.0.0.0:5060>
Call-ID: 1bf35bec-1a88-468e-bd17-dfa99086c457
CSeq: 23923 INVITE
Allow: OPTIONS, REGISTER, SUBSCRIBE, NOTIFY, PUBLISH, INVITE, ACK, BYE, CANCEL, UPDATE, PRACK, MESSAGE, REFER
Supported: 100rel, timer, replaces, norefersub, histinfo
Session-Expires: 1800
Min-SE: 90
P-Asserted-Identity: "MI 3" <sip:056003#172.20.1.8>
Max-Forwards: 70
User-Agent: FPBX-15.0.23(16.16.1)
Content-Type: application/sdp
Content-Length: 231
v=0
o=- 519853527 519853527 IN IP4 172.20.1.8
s=Asterisk
c=IN IP4 172.20.1.8
t=0 0
m=audio 14490 RTP/AVP 9 101
a=rtpmap:9 G722/8000
a=rtpmap:101 telephone-event/8000
a=fmtp:101 0-16
a=ptime:20
a=maxptime:150
a=sendrecv
--end msg--
16:52:37.918 pjsua_call.c .Incoming Request msg INVITE/cseq=23923 (rdata0x7f5f6c001c48)
16:52:37.919 pjsua_acc.c ..No available account to handle Request msg INVITE/cseq=23923 (rdata0x7f5f6c001c48)
16:52:37.919 pjsua_core.c ..TX 402 bytes Response msg 480/INVITE/cseq=23923 (tdta0x7f5f6c006b78) to UDP 172.20.1.8:5060:
SIP/2.0 480 Temporarily Unavailable
Via: SIP/2.0/UDP 0.0.0.0:5060;rport=5060;received=172.20.1.8;branch=z9hG4bKPjada6202d-813b-499c-9b5c-2ad5abf6706e
Call-ID: 1bf35bec-1a88-468e-bd17-dfa99086c457
From: "MI 3" <sip:056003#172.20.1.8>;tag=91efaf53-e6fb-45dc-b2d4-ddc99a6c3c36
To: <sip:056004#172.20.1.2;ob>;tag=z9hG4bKPjada6202d-813b-499c-9b5c-2ad5abf6706e
CSeq: 23923 INVITE
Content-Length: 0
--end msg--
16:52:37.919 pjsua_call.c ..Unable to accept incoming call (no available account)
16:52:37.921 pjsua_core.c .RX 433 bytes Request msg ACK/cseq=23923 (rdata0x7f5f6c001c48) from UDP 172.20.1.8:5060:
ACK sip:056004#172.20.1.2:5060;ob SIP/2.0
Via: SIP/2.0/UDP 0.0.0.0:5060;rport;branch=z9hG4bKPjada6202d-813b-499c-9b5c-2ad5abf6706e
From: "MI 3" <sip:056003#172.20.1.8>;tag=91efaf53-e6fb-45dc-b2d4-ddc99a6c3c36
To: <sip:056004#172.20.1.2;ob>;tag=z9hG4bKPjada6202d-813b-499c-9b5c-2ad5abf6706e
Call-ID: 1bf35bec-1a88-468e-bd17-dfa99086c457
CSeq: 23923 ACK
Max-Forwards: 70
User-Agent: FPBX-15.0.23(16.16.1)
Content-Length: 0
--end msg--
16:52:41.382 pjsua_core.c .RX 419 bytes Request msg OPTIONS/cseq=9130 (rdata0x7f5f6c001c48) from UDP 172.20.1.8:5060:
OPTIONS sip:056004#172.20.1.2:5060;ob SIP/2.0
Via: SIP/2.0/UDP 0.0.0.0:5060;rport;branch=z9hG4bKPj54cf9751-5357-4887-91d3-b8d97ea6d2f4
From: <sip:056004#172.20.1.8>;tag=9a799201-1424-418d-b5c4-44997fc40829
To: <sip:056004#172.20.1.2;ob>
Contact: <sip:056004#0.0.0.0:5060>
Call-ID: 84c421ff-ae98-475f-b11e-ac7cd27caa66
CSeq: 9130 OPTIONS
Max-Forwards: 70
User-Agent: FPBX-15.0.23(16.16.1)
Content-Length: 0
--end msg--
16:52:41.382 pjsua_core.c .TX 760 bytes Response msg 200/OPTIONS/cseq=9130 (tdta0x7f5f6c003c18) to UDP 172.20.1.8:5060:
SIP/2.0 200 OK
Via: SIP/2.0/UDP 0.0.0.0:5060;rport=5060;received=172.20.1.8;branch=z9hG4bKPj54cf9751-5357-4887-91d3-b8d97ea6d2f4
Call-ID: 84c421ff-ae98-475f-b11e-ac7cd27caa66
From: <sip:056004#172.20.1.8>;tag=9a799201-1424-418d-b5c4-44997fc40829
To: <sip:056004#172.20.1.2;ob>;tag=z9hG4bKPj54cf9751-5357-4887-91d3-b8d97ea6d2f4
CSeq: 9130 OPTIONS
Allow: PRACK, INVITE, ACK, BYE, CANCEL, UPDATE, INFO, SUBSCRIBE, NOTIFY, REFER, MESSAGE, OPTIONS
Accept: application/sdp, application/pidf+xml, application/xpidf+xml, application/simple-message-summary, message/sipfrag;version=2.0, application/im-iscomposing+xml, text/plain
Supported: replaces, 100rel, timer, norefersub, trickle-ice
Allow-Events: presence, message-summary, refer
Content-Length: 0
--end msg--
And not sure why it says pjsua_acc.c ..No available account to handle Request msg INVITE/cseq=23923 (rdata0x7f5f6c001c48)
Some idea? what part is bad implemented in my code? Maybe should I handle the initalise_sip_stack() function as a thread/process?
Thank you very much!

Python socket programmed web server doesnt send information to browser

I create a simple web server using python socket programming. When I access it using a socket programmed client I get this response (which seems to be good):
HTTP/1.0 200 OK
Content-Length: 145
Content-Type: text/html
"""<!DOCTYPE html>
<html>
<body>
<h2>HTML Links</h2>
<p>Visit our HTML tutorial</p>
</body>
</html>"""
However, when I try to access 127.0.0.1:80 on the browser it says:
127.0.0.1 didn’t send any data. ERR_EMPTY_RESPONSE
Web Server Code:
import socket
import os
def get_content_type(filename):
index = filename.rfind('.')
extension = filename[index+1:len(filename)]
if(extension == 'txt' or extension == 'html'):
return 'Content-Type: text/html\n'
elif(extension == 'jpg'):
return 'Content Type: image/jpeg\n'
elif(extension == 'js'):
return 'Content Type: text/javascript; charset=UTF 8\n'
elif(extension == 'css'):
return 'Content Type: text/css\n'
pass
def check_client_request(client_request):
request_splitted = client_request.split()
if(len(request_splitted) != 3):
return False
if(request_splitted[0] != 'GET'):
return False
if(request_splitted[1].find('http://') != 0):
return False
if(request_splitted[1].count('/') < 3):
return False
if(request_splitted[2] != 'HTTP/1.1\\r\\n'):
return False
return True
def recieve_client_request(client_socket):
client_request = client_socket.recv(1024)
return client_request.decode('utf-8')
def handle_client_request(request):
try:
filename = request.split()[1].split('/')[3]
except:
return 'File not found'
if(filename == ''):
filename = 'index.html'
path = f'C:\\Users\\Eitan\\Desktop\\Python-Course\\SOCKETWEBSERVER\\{filename}'
print(path)
response = ''
if(os.path.isfile(path)):
try:
requested_file = open(path, 'r')
file_content = requested_file.read()
requested_file.close()
response = 'HTTP/1.0 200 OK\n'
content_length = len(file_content.encode('utf-8'))
response += f'Content-Length: {content_length}\n'
response += get_content_type(filename)
response += '\n'
response += f'"""{file_content}"""'
except:
response = 'HTTP/1.1 404 Not Found\n'
else:
response = 'HTTP/1.1 404 Not Found\n'
return response
def send_response(client_socket, response):
try:
client_socket.send(response.encode('utf-8'))
print('Response Sent')
except:
print('Couldnt send response.')
def main():
server_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
server_socket.bind(('0.0.0.0', 80))
server_socket.listen(1)
while True:
client_socket = server_socket.accept()[0]
client_request = recieve_client_request(client_socket)
if(check_client_request(client_request)):
response = handle_client_request(client_request)
send_response(client_socket, response)
client_socket.close()
else:
client_socket.close()
if(__name__ == '__main__'):
main()
Client Code:
import socket
def main():
client_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
client_socket.connect(('127.0.0.1', 80))
request = input("Command: ").encode('utf-8')
client_socket.send(request)
response = client_socket.recv(1024)
print(response.decode('utf-8'))
if(__name__ == '__main__'):
main()
if(request_splitted[1].find('http://') != 0):
return False
You expect the browser to send a request like this
GET http://domain/page HTTP/1.1
...
But, a normal HTTP request does not include protocol and host but only the page, i.e. it looks like this
GET /page HTTP/1.1
...
Since you treat the valid request from the browser as invalid you close the connection and thus no response is sent to the browser.
Note that HTTP is not that simple as it might look. There is an actual standard for this which is quite long and which you are expected to follow when implementing a HTTP server or client.

How to pass Queue to baseHTTPServer

I'm using the example bellow with Thread, a simple http server to listen to post request and collect the data for the main process.
I want to convert it to use multiprocessing and passing a Queue in order to collect the POST data but I'm not sure how to pass it, any idea on how to do so?
from threading import Thread
from BaseHTTPServer import HTTPServer, BaseHTTPRequestHandler
from io import BytesIO
KEEP_RUNNING = True
COLLECT_POST_DATA = []
class SimpleHTTPRequestHandler(BaseHTTPRequestHandler):
def do_POST(self):
content_length = int(self.headers['Content-Length'])
body = self.rfile.read(content_length)
print("body: {}".format(body))
COLLECT_POST_DATA.append(body)
self.send_response(200)
self.end_headers()
response = BytesIO()
response.write(b'This is POST request. ')
response.write(b'Received: ')
response.write(body)
self.wfile.write(response.getvalue())
def run_server(port):
httpd = HTTPServer(('0.0.0.0', port), SimpleHTTPRequestHandler)
httpd.timeout = 1
while KEEP_RUNNING:
httpd.handle_request()
# httpd.serve_forever()
t = Thread(target = run_server, args=(8000,))
t.start()
# to kill
KEEP_RUNNING = False
So I worked it out:
import multiprocessing
from BaseHTTPServer import HTTPServer, BaseHTTPRequestHandler
from io import BytesIO
class QueuingHTTPServer(HTTPServer):
# def __init__(self, server_address, RequestHandlerClass, bind_and_activate=True, queue=False):
def __init__(self, server_address, RequestHandlerClass, queue, bind_and_activate=True):
HTTPServer.__init__(self, server_address, RequestHandlerClass, bind_and_activate)
self.queue = queue
class PostHTTPRequestHandler(BaseHTTPRequestHandler):
def do_POST(self):
content_length = int(self.headers['Content-Length'])
body = self.rfile.read(content_length)
print("body: {}".format(body))
self.send_response(200)
self.end_headers()
response = BytesIO()
response.write(b'This is POST request. ')
response.write(b'Received: ')
response.write(body)
self.wfile.write(response.getvalue())
self.server.queue.put(body)
def run_server(port, queue):
print('run_server')
httpd = QueuingHTTPServer(('0.0.0.0', port), PostHTTPRequestHandler, queue)
httpd.timeout = 2
while True:
httpd.handle_request()
# httpd.serve_forever()
queue = multiprocessing.Queue()
p = multiprocessing.Process(target=run_server, name='serve', args=(8000, queue))
p.start()
try it with:
curl hostip:8000 -m 5 -d"12.12.12.12"
Then from the script:
data = queue.get(timeout=2)
kill by:
p.terminate()

asyncore python hangs

I try to do simple async http client with asyncore:
This code works fine and output is (fast enought):
www.gmail.com : recv http code: 301
www.yandex.ru : recv http code: 200
www.python.org : recv http code: 200
www.google.ru : recv http code: 200
www.gravatar.com : recv http code: 302
www.com.com : recv http code: 302
www.yahoo.com : recv http code: 302
www.bom.com : recv http code: 301
But than i uncomment line with not exist host:
#c = AsyncHTTP('http://www.no-such-host.ru') #!this line breaks execution!
The execution breaks, code hangs for some time, output part of data and hangs with no last data output:
connection error: [Errno -5] No address associated with hostname
www.gmail.com : recv http code: 301
www.yandex.ru : recv http code: 200
www.yahoo.com : recv http code: 302
www.com.com : recv http code: 302
www.bom.com : recv http code: 301
www.gravatar.com : recv http code: 302
...
some hosts are lost here and long delay at start.
Why this happen and how to fix this?
# coding=utf-8
import asyncore
import string, socket
import StringIO
import mimetools, urlparse
class AsyncHTTP(asyncore.dispatcher):
# HTTP requestor
def __init__(self, uri):
asyncore.dispatcher.__init__(self)
self.uri = uri
# turn the uri into a valid request
scheme, host, path, params, query, fragment = urlparse.urlparse(uri)
assert scheme == "http", "only supports HTTP requests"
try:
host, port = string.split(host, ":", 1)
port = int(port)
except (TypeError, ValueError):
port = 80 # default port
if not path:
path = "/"
if params:
path = path + ";" + params
if query:
path = path + "?" + query
self.request = "GET %s HTTP/1.0\r\nHost: %s\r\n\r\n" % (path, host)
self.host = host
self.port = port
self.status = None
self.header = None
self.http_code = None
self.data = ""
# get things going!
self.create_socket(socket.AF_INET, socket.SOCK_STREAM)
#self.connect((host, port))
#return
try:
self.connect((host, port))
except Exception,e:
self.close()
self.handle_connect_expt(e)
def handle_connect(self):
self.send(self.request)
def handle_expt(self):
print "handle_expt error!"
self.close()
def handle_error(self):
print "handle_error error!"
self.close()
def handle_connect_expt(self,expt):
print "connection error:",expt
def handle_code(self):
print self.host," : ","recv http code: ",self.http_code
def handle_read(self):
data = self.recv(2048)
#print data
if not self.header:
self.data = self.data + data
try:
i = string.index(self.data, "\r\n\r\n")
except ValueError:
return # continue
else:
# parse header
fp = StringIO.StringIO(self.data[:i+4])
# status line is "HTTP/version status message"
status = fp.readline()
self.status = string.split(status, " ", 2)
self.http_code = self.status[1]
self.handle_code()
# followed by a rfc822-style message header
self.header = mimetools.Message(fp)
# followed by a newline, and the payload (if any)
data = self.data[i+4:]
self.data = ""
#header recived
#self.close()
def handle_close(self):
self.close()
c = AsyncHTTP('http://www.python.org')
c = AsyncHTTP('http://www.yandex.ru')
c = AsyncHTTP('http://www.google.ru')
c = AsyncHTTP('http://www.gmail.com')
c = AsyncHTTP('http://www.gravatar.com')
c = AsyncHTTP('http://www.yahoo.com')
c = AsyncHTTP('http://www.com.com')
c = AsyncHTTP('http://www.bom.com')
#c = AsyncHTTP('http://www.no-such-host.ru') #!this line breaks execution!
asyncore.loop()
ps: My system ubuntu 11.10 + python 2.7.2
You invoke a blocking name-resolution when you do self.connect((host, port)). Combined with your local DNS configuration, this is why your program has a long delay at startup.
An alternative to asyncore and figuring out how to do non-blocking name resolution yourself, you might think about using Twisted. Twisted's TCP connection setup API (mainly reactor.connectTCP or one of the APIs built on top of it) does not block. So a naive use of it will remain properly asynchronous.

Making HTTP HEAD request with urllib2 from Python 2

I'm trying to do a HEAD request of a page using Python 2.
I am trying
import misc_urllib2
.....
opender = urllib2.build_opener([misc_urllib2.MyHTTPRedirectHandler(), misc_urllib2.HeadRequest()])
with misc_urllib2.py containing
class HeadRequest(urllib2.Request):
def get_method(self):
return "HEAD"
class MyHTTPRedirectHandler(urllib2.HTTPRedirectHandler):
def __init__ (self):
self.redirects = []
def http_error_301(self, req, fp, code, msg, headers):
result = urllib2.HTTPRedirectHandler.http_error_301(
self, req, fp, code, msg, headers)
result.redirect_code = code
return result
http_error_302 = http_error_303 = http_error_307 = http_error_301
But I am getting
TypeError: __init__() takes at least 2 arguments (1 given)
If I just do
opender = urllib2.build_opener(misc_urllib2.MyHTTPRedirectHandler())
then it works fine
This works just fine:
import urllib2
request = urllib2.Request('http://localhost:8080')
request.get_method = lambda : 'HEAD'
response = urllib2.urlopen(request)
print response.info()
Tested with quick and dirty HTTPd hacked in python:
Server: BaseHTTP/0.3 Python/2.6.6
Date: Sun, 12 Dec 2010 11:52:33 GMT
Content-type: text/html
X-REQUEST_METHOD: HEAD
I've added a custom header field X-REQUEST_METHOD to show it works :)
Here is HTTPd log:
Sun Dec 12 12:52:28 2010 Server Starts - localhost:8080
localhost.localdomain - - [12/Dec/2010 12:52:33] "HEAD / HTTP/1.1" 200 -
Edit: there is also httplib2
import httplib2
h = httplib2.Http()
resp = h.request("http://www.google.com", 'HEAD')
Try httplib
>>> import httplib
>>> conn = httplib.HTTPConnection("www.google.com")
>>> conn.request("HEAD", "/index.html")
>>> res = conn.getresponse()
>>> print res.status, res.reason
200 OK
>>> print res.getheaders()
[('content-length', '0'), ('expires', '-1'), ('server', 'gws'), ('cache-control', 'private, max-age=0'), ('date', 'Sat, 20 Sep 2008 06:43:36 GMT'), ('content-type', 'text/html; charset=ISO-8859-1')]
See How do you send a HEAD HTTP request in Python 2?
The problem lies with your class HeadRequest, which inherits from urllib2.Request. According to doc, urllib2.Request.__init__ signature is
__init__(self, url, data=None, headers={}, origin_req_host=None, unverifiable=False)
so you must pass an url argument to it. In your second try, you just do not use HeadRequest, this is why it works.
you shoud not add HeadRequest to build_opener or add_handler it should be called like this
opener = urllib2.build_opener(MyHTTPRedirectHandler)
response = opener.open(HeadRequest(url))
print response.getheaders()

Categories

Resources