Trying to serve HTML5 <audio> element from Python+SSL to Android Chrome -


i have python-based web application server; great plain http. https, works browsers--except android chrome. chrome, html , icons fine on https, <audio> element fails start. see chrome pull 1 initial byte of mp3 (presumably way of testing file presence), served it. , chrome greys out <audio> element.

i've pulled same single byte using curl, , works fine:

curl -r 0-1 -k https://localhost:8083/foo.mp3 > foo1.mp3

i've added various delays , flushes, without fixing problem.

it seem not content-range issue, i've changed code return full mp3 (with 200 code), same chrome behavior.

firefox happy (both android , linux), midori (a webkit based browser). on linux, chrome/chromium both happy it. android chrome--no luck.

i've extracted relevant bits of code; i'm assuming there's http nicety i'm missing (and, believe me, i've been looking). exercise it, plug in self-signed certificate pair @ hard-coded files "server.key" , "server.crt". put mp3 of choice @ "foo.mp3" , point browser at:

https://localhost:8083 

tia suggestions! i'm sorry code runs little long; extracted bits reproduce this. left off range support, didn't want chase legacy code paths of chrome.

# # debug.py #       sample code snippet debug chrome html5 <audio> ssl problem # import pdb import sys, socket, ssl, threading, os, time basehttpserver import basehttprequesthandler  ourmp3 = "foo.mp3"  # decode "range:" header option, return #  (offset,length) or none if don't #  region (tbd, multiple ranges , #  multipart) # we're passed file's os.stat #  range: field value. def decode_range(st, range):     # byte units, please     if not range.startswith("bytes="):         return none     range = range[6:]      # single range     if ',' in range:         return none      # start offset     if range[0] == '-':         range = range[1:]         if not range.isdigit():             return none         val1 = int(range)         if val1 >= st.st_size:             return none         return (0, val1)      # offset end...     elif range[-1] == '-':         range = range[:-1]         if not range.isdigit():             return none         val2 = int(range)         if val2 >= st.st_size:             return none         return (val2, st.st_size - val2)      # offset1 offset2     else:         parts = range.split('-')         if len(parts) != 2:             return none         if not all(p.isdigit() p in parts):             return none         val1 = int(parts[0])         val2 = int(parts[1])         if val1 >= val2:             return none         return (val1, val2-val1)  class client(basehttprequesthandler):      # send mp3 file ourmp3     def send_mp3(self):          # simplicity, big buffer         f = open(ourmp3, "rb")         st = os.fstat(f.fileno())         buf = f.read()         f.close()          # partial         ranged = 'range' in self.headers         if ranged:             tup = decode_range(st, self.headers['range'])             assert tup             startoff,nbyte = tup             assert (nbyte + startoff) <= len(buf)             self.send_response(206)         else:             startoff = 0             nbyte = len(buf)             self.send_response(200)          # headers         self.send_response(200)         self.send_header("content-type", "audio/mpeg")         self.send_header("content-length", nbyte)         if ranged:             self.send_header("content-range",              "bytes %d-%d/%d" % (startoff, startoff+nbyte-1, st.st_size))         self.send_header("last-modified",          time.asctime(time.localtime(st.st_mtime)))         self.end_headers()          # let our upper layers write (or discard         #  it, head)         return buf[startoff:(startoff+nbyte)]      # send html5 <audio> player our mp3     def send_root(self):         buf = \ ''' <html><head><title>test mp3</title></head>\r audio player:<br>\r <body><audio src="foo.mp3" controls autoplay></audio></body>\r </html>\r '''         self.send_response(200)         self.send_header("content-type", "text/html")         self.send_header("content-length", len(buf))         self.end_headers()         return buf      # process http get's     def do_get(self):         sys.stderr.write("get %r\n" % (self.path,))         path = self.path          # root; our html play mp3         if (not path) or (path == '/'):             buf = self.send_root()          # our mp3         elif path.endswith(ourmp3):             buf = self.send_mp3()          # that's serve         else:             self.send_error(404)             return none          # body?         if buf:             self.wfile.write(buf)  # dispatch web client def serve_client(conn, tup):     h = client(conn, tup, none)     conn.close()     sys.exit(0)  # endless server loop on port 8083 def server():     s = socket.socket(socket.af_inet, socket.sock_stream)     s = ssl.wrap_socket(s,         "server.key", "server.crt",         server_side=true, suppress_ragged_eofs=false,         do_handshake_on_connect=false)      s.bind( ("", 8083) )     s.listen(10)     while true:         conn,tup = s.accept()         sys.stderr.write("client %r\n" % (tup,))         conn.do_handshake()         t = threading.thread(target=serve_client, args=(conn,tup))         t.start()  if __name__ == "__main__":     server() 


Comments

Popular posts from this blog

javascript - jQuery: Add class depending on URL in the best way -

caching - How to check if a url path exists in the service worker cache -

Redirect to a HTTPS version using .htaccess -