<s> import re <EOL> import coro <EOL> import coro . read_stream <EOL> from protocol import http_file , header_set , latch <EOL> W = coro . write_stderr <EOL> class HTTP_Protocol_Error ( Exception ) : <EOL> pass <EOL> class Bad_Response ( HTTP_Protocol_Error ) : <EOL> pass <EOL> class request : <EOL> def __init__ ( self , method , uri , headers , content = None , force = True ) : <EOL> self . method = method <EOL> self . uri = uri <EOL> self . qheaders = headers <EOL> self . latch = latch ( ) <EOL> self . force = force <EOL> self . qcontent = content <EOL> self . content = None <EOL> self . response = None <EOL> self . rheader = None <EOL> self . rfile = None <EOL> def wake ( self ) : <EOL> "<STR_LIT>" <EOL> if self . rfile and self . force : <EOL> self . content = self . rfile . read ( ) <EOL> self . latch . wake_all ( ) <EOL> if self . rfile and not self . force : <EOL> self . rfile . wait ( ) <EOL> def wait ( self ) : <EOL> "<STR_LIT>" <EOL> return self . latch . wait ( ) <EOL> def abort ( self ) : <EOL> "<STR_LIT>" <EOL> self . latch . wake_all ( ) <EOL> if self . rfile : <EOL> self . rfile . abort ( ) <EOL> def has_body ( self ) : <EOL> h = self . rheader <EOL> if h . has_key ( '<STR_LIT>' ) : <EOL> return True <EOL> else : <EOL> probe = h . get_one ( '<STR_LIT>' ) <EOL> if probe : <EOL> try : <EOL> size = int ( probe ) <EOL> if size == <NUM_LIT:0> : <EOL> return False <EOL> elif size > <NUM_LIT:0> : <EOL> return True <EOL> else : <EOL> return False <EOL> except ValueError : <EOL> return False <EOL> elif h . test ( '<STR_LIT>' , '<STR_LIT>' ) and self . method == '<STR_LIT:GET>' : <EOL> return True <EOL> else : <EOL> return False <EOL> class client : <EOL> def __init__ ( self , host , port = <NUM_LIT> , conn = None , inflight = <NUM_LIT:100> ) : <EOL> self . host = host <EOL> self . inflight = coro . semaphore ( inflight ) <EOL> if conn is None : <EOL> self . conn = coro . tcp_sock ( ) <EOL> else : <EOL> self . conn = conn <EOL> self . conn . connect ( ( host , port ) ) <EOL> self . stream = coro . read_stream . sock_stream ( self . conn ) <EOL> self . pending = coro . fifo ( ) <EOL> coro . spawn ( self . read_thread ) <EOL> def read_thread ( self ) : <EOL> while <NUM_LIT:1> : <EOL> req = self . pending . pop ( ) <EOL> if req is None : <EOL> break <EOL> else : <EOL> self . _read_message ( req ) <EOL> if not req . response : <EOL> break <EOL> else : <EOL> req . wake ( ) <EOL> def close ( self ) : <EOL> self . pending . push ( None ) <EOL> self . conn . close ( ) <EOL> response_re = re . compile ( '<STR_LIT>' ) <EOL> def _read_message ( self , req ) : <EOL> line = self . stream . read_line ( ) <EOL> if not line : <EOL> raise HTTP_Protocol_Error ( '<STR_LIT>' ) <EOL> req . response = line [ : - <NUM_LIT:2> ] <EOL> m = self . response_re . match ( req . response ) <EOL> if not m : <EOL> raise Bad_Response ( req . response ) <EOL> else : <EOL> req . version , req . reply_code , req . reason = m . groups ( ) <EOL> lines = [ ] <EOL> while <NUM_LIT:1> : <EOL> line = self . stream . read_line ( ) <EOL> if not line : <EOL> raise HTTP_Protocol_Error ( '<STR_LIT>' ) <EOL> elif line == '<STR_LIT:\r\n>' : <EOL> break <EOL> else : <EOL> lines . append ( line [ : - <NUM_LIT:2> ] ) <EOL> req . rheader = h = header_set ( lines ) <EOL> if req . has_body ( ) : <EOL> req . rfile = http_file ( h , self . stream ) <EOL> def send_request ( self , method , uri , headers , content = None , force = False ) : <EOL> try : <EOL> self . inflight . acquire ( <NUM_LIT:1> ) <EOL> req = request ( method , uri , headers , content , force ) <EOL> self . _send_request ( method , uri , headers , content ) <EOL> self . pending . push ( req ) <EOL> return req <EOL> finally : <EOL> self . inflight . release ( <NUM_LIT:1> ) <EOL> def _send_request ( self , method , uri , headers , content ) : <EOL> if not headers . has_key ( '<STR_LIT:host>' ) : <EOL> headers [ '<STR_LIT:host>' ] = self . host <EOL> if content : <EOL> if type ( content ) is str : <EOL> headers [ '<STR_LIT>' ] = len ( content ) <EOL> elif not headers . has_key ( '<STR_LIT>' ) : <EOL> headers [ '<STR_LIT>' ] = '<STR_LIT>' <EOL> req = ( <EOL> '<STR_LIT>' <EOL> '<STR_LIT>' % ( method , uri , headers ) <EOL> ) <EOL> self . conn . send ( req ) <EOL> if content : <EOL> if type ( content ) is str : <EOL> self . conn . send ( content ) <EOL> elif headers . has_key ( '<STR_LIT>' ) : <EOL> clen = int ( headers . get_one ( '<STR_LIT>' ) ) <EOL> slen = <NUM_LIT:0> <EOL> for block in content : <EOL> self . conn . send ( block ) <EOL> slen += len ( block ) <EOL> if slen > clen : <EOL> raise HTTP_Protocol_Error ( "<STR_LIT>" , clen , slen ) <EOL> else : <EOL> if slen != clen : <EOL> raise HTTP_Protocol_Error ( "<STR_LIT>" , clen , slen ) <EOL> else : <EOL> for block in content : <EOL> if block : <EOL> self . conn . writev ( [ '<STR_LIT>' % ( len ( block ) , ) , block ] ) <EOL> self . conn . send ( '<STR_LIT>' ) <EOL> def GET ( self , uri , ** headers ) : <EOL> headers = header_set ( ) . from_keywords ( headers ) <EOL> req = self . send_request ( '<STR_LIT:GET>' , uri , headers , force = True ) <EOL> req . wait ( ) <EOL> return req <EOL> def GET_file ( self , uri , ** headers ) : <EOL> headers = header_set ( ) . from_keywords ( headers ) <EOL> req = self . send_request ( '<STR_LIT:GET>' , uri , headers , force = False ) <EOL> req . wait ( ) <EOL> return req <EOL> def PUT ( self , uri , content , ** headers ) : <EOL> headers = header_set ( ) . from_keywords ( headers ) <EOL> req = self . send_request ( '<STR_LIT>' , uri , headers , content , force = True ) <EOL> req . wait ( ) <EOL> return req <EOL> def POST ( self , uri , content , ** headers ) : <EOL> headers = header_set ( ) . from_keywords ( headers ) <EOL> req = self . send_request ( '<STR_LIT:POST>' , uri , headers , content , force = True ) <EOL> req . wait ( ) <EOL> return req </s>
