<s> import re <EOL> import zlib <EOL> try : <EOL> import urlparse <EOL> from urllib import unquote <EOL> except ImportError : <EOL> import urllib . parse as urlparse <EOL> from urllib . parse import unquote <EOL> from circuits . six import b , bytes_to_str , MAXSIZE <EOL> from . . headers import Headers <EOL> METHOD_RE = re . compile ( "<STR_LIT>" ) <EOL> VERSION_RE = re . compile ( "<STR_LIT>" ) <EOL> STATUS_RE = re . compile ( "<STR_LIT>" ) <EOL> HEADER_RE = re . compile ( "<STR_LIT>" ) <EOL> BAD_FIRST_LINE = <NUM_LIT:0> <EOL> INVALID_HEADER = <NUM_LIT:1> <EOL> INVALID_CHUNK = <NUM_LIT:2> <EOL> class InvalidRequestLine ( Exception ) : <EOL> """<STR_LIT>""" <EOL> class InvalidHeader ( Exception ) : <EOL> """<STR_LIT>""" <EOL> class InvalidChunkSize ( Exception ) : <EOL> """<STR_LIT>""" <EOL> class HttpParser ( object ) : <EOL> def __init__ ( self , kind = <NUM_LIT:2> , decompress = False ) : <EOL> self . kind = kind <EOL> self . decompress = decompress <EOL> self . errno = None <EOL> self . errstr = "<STR_LIT>" <EOL> self . _buf = [ ] <EOL> self . _version = None <EOL> self . _method = None <EOL> self . _status_code = None <EOL> self . _status = None <EOL> self . _reason = None <EOL> self . _url = None <EOL> self . _path = None <EOL> self . _query_string = None <EOL> self . _headers = Headers ( [ ] ) <EOL> self . _environ = dict ( ) <EOL> self . _chunked = False <EOL> self . _body = [ ] <EOL> self . _trailers = None <EOL> self . _partial_body = False <EOL> self . _clen = None <EOL> self . _clen_rest = None <EOL> self . __on_firstline = False <EOL> self . __on_headers_complete = False <EOL> self . __on_message_begin = False <EOL> self . __on_message_complete = False <EOL> self . __decompress_obj = None <EOL> def get_version ( self ) : <EOL> return self . _version <EOL> def get_method ( self ) : <EOL> return self . _method <EOL> def get_status_code ( self ) : <EOL> return self . _status_code <EOL> def get_url ( self ) : <EOL> return self . _url <EOL> def get_scheme ( self ) : <EOL> return self . _scheme <EOL> def get_path ( self ) : <EOL> return self . _path <EOL> def get_query_string ( self ) : <EOL> return self . _query_string <EOL> def get_headers ( self ) : <EOL> return self . _headers <EOL> def recv_body ( self ) : <EOL> """<STR_LIT>""" <EOL> body = b ( "<STR_LIT>" ) . join ( self . _body ) <EOL> self . _body = [ ] <EOL> self . _partial_body = False <EOL> return body <EOL> def recv_body_into ( self , barray ) : <EOL> """<STR_LIT>""" <EOL> l = len ( barray ) <EOL> body = b ( "<STR_LIT>" ) . join ( self . _body ) <EOL> m = min ( len ( body ) , l ) <EOL> data , rest = body [ : m ] , body [ m : ] <EOL> barray [ <NUM_LIT:0> : m ] = data <EOL> if not rest : <EOL> self . _body = [ ] <EOL> self . _partial_body = False <EOL> else : <EOL> self . _body = [ rest ] <EOL> return m <EOL> def is_upgrade ( self ) : <EOL> """<STR_LIT>""" <EOL> return self . _headers . get ( '<STR_LIT>' , "<STR_LIT>" ) . lower ( ) == "<STR_LIT>" <EOL> def is_headers_complete ( self ) : <EOL> """<STR_LIT>""" <EOL> return self . __on_headers_complete <EOL> def is_partial_body ( self ) : <EOL> """<STR_LIT>""" <EOL> return self . _partial_body <EOL> def is_message_begin ( self ) : <EOL> """<STR_LIT>""" <EOL> return self . __on_message_begin <EOL> def is_message_complete ( self ) : <EOL> """<STR_LIT>""" <EOL> return self . __on_message_complete <EOL> def is_chunked ( self ) : <EOL> """<STR_LIT>""" <EOL> return self . _chunked <EOL> def should_keep_alive ( self ) : <EOL> """<STR_LIT>""" <EOL> hconn = self . _headers . get ( '<STR_LIT>' , "<STR_LIT>" ) . lower ( ) <EOL> if hconn == "<STR_LIT>" : <EOL> return False <EOL> elif hconn == "<STR_LIT>" : <EOL> return True <EOL> return self . _version == ( <NUM_LIT:1> , <NUM_LIT:1> ) <EOL> def execute ( self , data , length ) : <EOL> if length == <NUM_LIT:0> : <EOL> self . on_message_complete = True <EOL> return length <EOL> nb_parsed = <NUM_LIT:0> <EOL> while True : <EOL> if not self . __on_firstline : <EOL> idx = data . find ( b ( "<STR_LIT:\r\n>" ) ) <EOL> if idx < <NUM_LIT:0> : <EOL> self . _buf . append ( data ) <EOL> return len ( data ) <EOL> else : <EOL> self . __on_firstline = True <EOL> self . _buf . append ( data [ : idx ] ) <EOL> first_line = bytes_to_str ( b ( "<STR_LIT>" ) . join ( self . _buf ) ) <EOL> nb_parsed = nb_parsed + idx + <NUM_LIT:2> <EOL> rest = data [ idx + <NUM_LIT:2> : ] <EOL> data = b ( "<STR_LIT>" ) <EOL> if self . _parse_firstline ( first_line ) : <EOL> self . _buf = [ rest ] <EOL> else : <EOL> return nb_parsed <EOL> elif not self . __on_headers_complete : <EOL> if data : <EOL> self . _buf . append ( data ) <EOL> data = b ( "<STR_LIT>" ) <EOL> try : <EOL> to_parse = b ( "<STR_LIT>" ) . join ( self . _buf ) <EOL> ret = self . _parse_headers ( to_parse ) <EOL> if not ret : <EOL> return length <EOL> nb_parsed = nb_parsed + ( len ( to_parse ) - ret ) <EOL> except InvalidHeader as e : <EOL> self . errno = INVALID_HEADER <EOL> self . errstr = str ( e ) <EOL> return nb_parsed <EOL> elif not self . __on_message_complete : <EOL> if not self . __on_message_begin : <EOL> self . __on_message_begin = True <EOL> if data : <EOL> self . _buf . append ( data ) <EOL> data = b ( "<STR_LIT>" ) <EOL> ret = self . _parse_body ( ) <EOL> if ret is None : <EOL> return length <EOL> elif ret < <NUM_LIT:0> : <EOL> return ret <EOL> elif ret == <NUM_LIT:0> : <EOL> self . __on_message_complete = True <EOL> return length <EOL> else : <EOL> nb_parsed = max ( length , ret ) <EOL> else : <EOL> return <NUM_LIT:0> <EOL> def _parse_firstline ( self , line ) : <EOL> try : <EOL> if self . kind == <NUM_LIT:2> : <EOL> try : <EOL> self . _parse_request_line ( line ) <EOL> except InvalidRequestLine : <EOL> self . _parse_response_line ( line ) <EOL> elif self . kind == <NUM_LIT:1> : <EOL> self . _parse_response_line ( line ) <EOL> elif self . kind == <NUM_LIT:0> : <EOL> self . _parse_request_line ( line ) <EOL> except InvalidRequestLine as e : <EOL> self . errno = BAD_FIRST_LINE <EOL> self . errstr = str ( e ) <EOL> return False <EOL> return True <EOL> def _parse_response_line ( self , line ) : <EOL> bits = line . split ( None , <NUM_LIT:1> ) <EOL> if len ( bits ) != <NUM_LIT:2> : <EOL> raise InvalidRequestLine ( line ) <EOL> matchv = VERSION_RE . match ( bits [ <NUM_LIT:0> ] ) <EOL> if matchv is None : <EOL> raise InvalidRequestLine ( "<STR_LIT>" % bits [ <NUM_LIT:0> ] ) <EOL> self . _version = ( int ( matchv . group ( <NUM_LIT:1> ) ) , int ( matchv . group ( <NUM_LIT:2> ) ) ) <EOL> matchs = STATUS_RE . match ( bits [ <NUM_LIT:1> ] ) <EOL> if matchs is None : <EOL> raise InvalidRequestLine ( "<STR_LIT>" . format ( bits [ <NUM_LIT:1> ] ) ) <EOL> self . _status = bits [ <NUM_LIT:1> ] <EOL> self . _status_code = int ( matchs . group ( <NUM_LIT:1> ) ) <EOL> self . _reason = matchs . group ( <NUM_LIT:2> ) <EOL> def _parse_request_line ( self , line ) : <EOL> bits = line . split ( None , <NUM_LIT:2> ) <EOL> if len ( bits ) != <NUM_LIT:3> : <EOL> raise InvalidRequestLine ( line ) <EOL> if not METHOD_RE . match ( bits [ <NUM_LIT:0> ] ) : <EOL> raise InvalidRequestLine ( "<STR_LIT>" % bits [ <NUM_LIT:0> ] ) <EOL> self . _method = bits [ <NUM_LIT:0> ] . upper ( ) <EOL> self . _url = bits [ <NUM_LIT:1> ] <EOL> parts = urlparse . urlsplit ( bits [ <NUM_LIT:1> ] ) <EOL> self . _scheme = parts . scheme or None <EOL> self . _path = parts . path or "<STR_LIT>" <EOL> self . _query_string = parts . query or "<STR_LIT>" <EOL> if parts . fragment : <EOL> raise InvalidRequestLine ( <EOL> "<STR_LIT>" <EOL> ) <EOL> match = VERSION_RE . match ( bits [ <NUM_LIT:2> ] ) <EOL> if match is None : <EOL> raise InvalidRequestLine ( "<STR_LIT>" % bits [ <NUM_LIT:2> ] ) <EOL> self . _version = ( int ( match . group ( <NUM_LIT:1> ) ) , int ( match . group ( <NUM_LIT:2> ) ) ) <EOL> if hasattr ( self , '<STR_LIT>' ) : <EOL> self . _environ . update ( { <EOL> "<STR_LIT>" : self . _path , <EOL> "<STR_LIT>" : self . _query_string , <EOL> "<STR_LIT>" : self . _url , <EOL> "<STR_LIT>" : self . _method , <EOL> "<STR_LIT>" : bits [ <NUM_LIT:2> ] } ) <EOL> def _parse_headers ( self , data ) : <EOL> idx = data . find ( b ( "<STR_LIT>" ) ) <EOL> if idx < <NUM_LIT:0> : <EOL> return False <EOL> lines = [ bytes_to_str ( line ) + "<STR_LIT:\r\n>" <EOL> for line in data [ : idx ] . split ( b ( "<STR_LIT:\r\n>" ) ) ] <EOL> while len ( lines ) : <EOL> curr = lines . pop ( <NUM_LIT:0> ) <EOL> if curr . find ( "<STR_LIT::>" ) < <NUM_LIT:0> : <EOL> raise InvalidHeader ( "<STR_LIT>" % curr . strip ( ) ) <EOL> name , value = curr . split ( "<STR_LIT::>" , <NUM_LIT:1> ) <EOL> name = name . rstrip ( "<STR_LIT>" ) . upper ( ) <EOL> if HEADER_RE . search ( name ) : <EOL> raise InvalidHeader ( "<STR_LIT>" % name ) <EOL> name , value = name . strip ( ) , [ value . lstrip ( ) ] <EOL> while len ( lines ) and lines [ <NUM_LIT:0> ] . startswith ( ( "<STR_LIT:U+0020>" , "<STR_LIT:\t>" ) ) : <EOL> value . append ( lines . pop ( <NUM_LIT:0> ) ) <EOL> value = '<STR_LIT>' . join ( value ) . rstrip ( ) <EOL> self . _headers . add_header ( name , value ) <EOL> key = '<STR_LIT>' % name . upper ( ) . replace ( '<STR_LIT:->' , '<STR_LIT:_>' ) <EOL> self . _environ [ key ] = value <EOL> clen = self . _headers . get ( '<STR_LIT>' ) <EOL> te = self . _headers . get ( '<STR_LIT>' , '<STR_LIT>' ) . lower ( ) <EOL> if clen is not None : <EOL> try : <EOL> self . _clen_rest = self . _clen = int ( clen ) <EOL> except ValueError : <EOL> pass <EOL> else : <EOL> self . _chunked = ( te == '<STR_LIT>' ) <EOL> if not self . _chunked : <EOL> self . _clen_rest = MAXSIZE <EOL> encoding = self . _headers . get ( '<STR_LIT>' ) <EOL> if self . decompress : <EOL> if encoding == "<STR_LIT>" : <EOL> self . __decompress_obj = zlib . decompressobj ( <NUM_LIT:16> + zlib . MAX_WBITS ) <EOL> elif encoding == "<STR_LIT>" : <EOL> self . __decompress_obj = zlib . decompressobj ( ) <EOL> rest = data [ idx + <NUM_LIT:4> : ] <EOL> self . _buf = [ rest ] <EOL> self . __on_headers_complete = True <EOL> return len ( rest ) <EOL> def _parse_body ( self ) : <EOL> if not self . _chunked : <EOL> body_part = b ( "<STR_LIT>" ) . join ( self . _buf ) <EOL> self . _clen_rest -= len ( body_part ) <EOL> if self . __decompress_obj is not None : <EOL> body_part = self . __decompress_obj . decompress ( body_part ) <EOL> self . _partial_body = True <EOL> self . _body . append ( body_part ) <EOL> self . _buf = [ ] <EOL> if self . _clen_rest <= <NUM_LIT:0> : <EOL> self . __on_message_complete = True <EOL> return <EOL> else : <EOL> data = b ( "<STR_LIT>" ) . join ( self . _buf ) <EOL> try : <EOL> size , rest = self . _parse_chunk_size ( data ) <EOL> except InvalidChunkSize as e : <EOL> self . errno = INVALID_CHUNK <EOL> self . errstr = "<STR_LIT>" % str ( e ) <EOL> return - <NUM_LIT:1> <EOL> if size == <NUM_LIT:0> : <EOL> return size <EOL> if size is None or len ( rest ) < size : <EOL> return None <EOL> body_part , rest = rest [ : size ] , rest [ size : ] <EOL> if len ( rest ) < <NUM_LIT:2> : <EOL> self . errno = INVALID_CHUNK <EOL> self . errstr = "<STR_LIT>" % data <EOL> return - <NUM_LIT:1> <EOL> if self . __decompress_obj is not None : <EOL> body_part = self . __decompress_obj . decompress ( body_part ) <EOL> self . _partial_body = True <EOL> self . _body . append ( body_part ) <EOL> self . _buf = [ rest [ <NUM_LIT:2> : ] ] <EOL> return len ( rest ) <EOL> def _parse_chunk_size ( self , data ) : <EOL> idx = data . find ( b ( "<STR_LIT:\r\n>" ) ) <EOL> if idx < <NUM_LIT:0> : <EOL> return None , None <EOL> line , rest_chunk = data [ : idx ] , data [ idx + <NUM_LIT:2> : ] <EOL> chunk_size = line . split ( b ( "<STR_LIT:;>" ) , <NUM_LIT:1> ) [ <NUM_LIT:0> ] . strip ( ) <EOL> try : <EOL> chunk_size = int ( chunk_size , <NUM_LIT:16> ) <EOL> except ValueError : <EOL> raise InvalidChunkSize ( chunk_size ) <EOL> if chunk_size == <NUM_LIT:0> : <EOL> self . _parse_trailers ( rest_chunk ) <EOL> return <NUM_LIT:0> , None <EOL> return chunk_size , rest_chunk <EOL> def _parse_trailers ( self , data ) : <EOL> idx = data . find ( b ( "<STR_LIT>" ) ) <EOL> if data [ : <NUM_LIT:2> ] == b ( "<STR_LIT:\r\n>" ) : <EOL> self . _trailers = self . _parse_headers ( data [ : idx ] ) </s>
