def test_request_version09(self): "Test request output for http 0.9" request = (b"GET /foo\r\n" b"Hello, how are you?\r\n" b"\r\n") req = Requests().parse(request) obtained = str(req).split(u'\n') should = [(u'******INVALID Requests STREAM <' u' Has invalid Message;>******'), u'-1 Requests-', u'---', u'****INVALID Request < Bad First line in Request;>****', u' [Req. 1st line]'] if sys.version_info[0] < 3: should.append(u'**(raw):GET /foo\r'), should.append(u'**'), else: should.append(u"**(raw):b'GET /foo\\r\\n'**"), should.append(u'**INVALID FIRST LINE < Maybe an HTTP/0.9 request;>**') should.append(u'[GET]<SP> [/foo] HTTP/[0][.][9] [[CR][LF]]') should.append(u' [Req. Headers]') should.append(u' [Req. Body] (size 23)') if sys.version_info[0] < 3: # python2 should.append(u'Hello, how are you?\r') should.append(u'\r') should.append(u'') else: should.append(u"b'Hello, how are you?\\r\\n\\r\\n'"), should.append(u' ++++++++++++++++++++++++++++++++++++++') should.append(u'') should.append(u'---') self.assertEqual(should, obtained)
def test_request_bad_first_line_1(self): "Test various bad first lines." request = (b"GET\00/foo HTTP/1.1\r\n" b"\r\n") req = Requests().parse(request) obtained = str(req).split(u'\n') should = [(u'******INVALID Requests STREAM <' u' Has invalid Message;>******'), u'-1 Requests-', u'---', u'****INVALID Request < Bad First line in Request;>****', u' [Req. 1st line]'] if sys.version_info[0] < 3: should.append(u'**(raw):GET\x00/foo HTTP/1.1\r'), should.append(u'**'), else: should.append(u"**(raw):b'GET\\x00/foo HTTP/1.1\\r\\n'**"), should.append((u'**INVALID FIRST LINE < Bad character detected;' u' Invalid Request method; Maybe an HTTP/0.9 request;' u' Message should be Rejected;>**')) should.append((u'[GET<Err><Err><Err><Err><Err>]<SP>' u' [<Err>TTP/1.1] HTTP/[0][.][9] [[CR][LF]]')) should.append(u' [Req. Headers]') should.append(u' [Req. Body] (size 2)') if sys.version_info[0] < 3: # python2 should.append(u'\r') should.append(u'') else: should.append(u"b'\\r\\n'"), should.append(u' ++++++++++++++++++++++++++++++++++++++') should.append(u'') should.append(u'---') self.assertEqual(should, obtained)
def test_regular_request(self): "Test regular request output" request = (b"GET /foo HTTP/1.0\r\n" b"Host: example.com\r\n" b"Header1: value1\r\n" b"Header2: value2\r\n" b"Content-Length: 18\r\n" b"\r\n" b"This is the body\r\n") req = Requests().parse(request) obtained = str(req).split(u'\n') should = [ u'-1 Requests-', u'---', u' [Req. 1st line]', u'[GET]<SP> [/foo]<SP> HTTP/[1][.][0] [[CR][LF]]', u' [Req. Headers]', u'[HOST] [:]<SP> [example.com] [[CR][LF]]', u'[HEADER1] [:]<SP> [value1] [[CR][LF]]', u'[HEADER2] [:]<SP> [value2] [[CR][LF]]', u'[CONTENT-LENGTH] [:]<SP> [18] [[CR][LF]]', u' [Req. Body] (size 18)' ] if sys.version_info[0] < 3: # python2 should.append(u'This is the body\r') should.append(u'') else: should.append(u"b'This is the body\\r\\n'"), should.append(u' ++++++++++++++++++++++++++++++++++++++') should.append(u'') should.append(u'---') self.assertEqual(should, obtained)
def test_request_multiline_headers(self): "Test multiline headers output" request = (b"GET /foo HTTP/1.0\r\n" b"Host: example.com\r\n" b"H1: v1\r\n" b" H2: v2\r\n" b" H3: v3\r\n" b"foo: bar bar\r\n" b"H4:\r\n" b" H5:v5\r\n" b"\r\n") req = Requests().parse(request) obtained = str(req).split(u'\n') should = [ u'-1 Requests-', u'---', u'****BAD Request < Has invalid Header;>****', u' [Req. 1st line]', u'[GET]<SP> [/foo]<SP> HTTP/[1][.][0] [[CR][LF]]', u' [Req. Headers]', u'[HOST] [:]<SP> [example.com] [[CR][LF]]', u'**BAD HEADER < Optional Multiline Header merged;>**', (u'[H1] [:]<SP> [v1<SP>H2:<SP>v2<SP>H3:<SP>v3]' u' [[CR][LF]]'), u'[FOO] [:]<SP> [bar<SP>bar] [[CR][LF]]', u'**BAD HEADER < Optional Multiline Header merged;>**', (u'[H4] [:]<SP> [<SP>H5:v5]' u' [[CR][LF]]'), u' [Req. Body] (size 0)' ] if sys.version_info[0] < 3: # python2 should.append(u'') else: should.append(u"b''"), should.append(u' ++++++++++++++++++++++++++++++++++++++') should.append(u'') should.append(u'---') self.assertEqual(should, obtained)
class Worker(object): request = None _sock = None _addr = None name = u'' ready = True output = b'' test_id = None behavior = None default_behavior = None test_behavior = None keepalive = True out_queue = None def __init__(self, name, out_queue=None): self.config = ConfigFactory.getConfig() self.name = name self.output = b'' self.stream = b'' self.keepalive = True self._sock = None self._sock_accept_reads = False self.out_queue = out_queue self.initDefaultBehavior() self.setReady() def setReady(self): self.ready = True self.keepalive = True self.output = b'' self.stream = b'' self.test_id = None self.test_behavior = None self._sock = None self._sock_accept_reads = False def initDefaultBehavior(self): self.default_behavior = Behavior() self.default_behavior.setRegularDefaults() def init(self, sock, address): self.ready = False self._sock = sock self._addr = address self._sock_accept_reads = True def close(self): if not self.ready: # this will also call setReady() self.close_socket() def inmsg(self, message): inmsg(message, prefix=u'BACKEND {0}> '.format(self.name), color='blue') def outmsg(self, message): outmsg(message, prefix=u'BACKEND {0}> '.format(self.name), color='yellow') def setTestId(self, id): self.test_id = id def setTestBehavior(self, behavior): self.test_behavior = behavior def getTestBehavior(self): if self.test_behavior is not None: return self.test_behavior else: self.default_behavior def close_socket_for_read(self): """Close the server-client socket for reads incoming from client. We do not completly close the socket right now to allow late reads in the client side. But this socket will soon be closed. """ if self._sock is not None: self.outmsg("Closing socket for reads") try: self._sock.shutdown(socket.SHUT_RD) except Exception: # already closed pass self._sock_accept_reads = False def close_socket(self): if self._sock is not None: self.outmsg("Closing socket") try: self._sock.shutdown(socket.SHUT_RDWR) except Exception: # already closed pass try: self._sock.close() except: pass self._sock = None self.setReady() def write_socket(self): if self.output is not None and self.output != b'': self.outmsg(self.output) self._sock.sendall(self.output) self.output = b'' if not self.keepalive: self.close_socket_for_read() def read_socket(self): if not self._sock_accept_reads: # This is for sockets that we decided to cut readings from. # like after a 0.9 message raw = b'' else: try: raw = self._sock.recv(self.config.getint( 'BACKEND_SOCK_READ_SIZE')) except ConnectionResetError: # python3 raw = b'' except socket.error as serr: # python2 support if serr.errno != errno.ECONNRESET: # that's another problem raise # [Errno 104] Connection reset by peer raw = b'' self.inmsg(str(raw)) if b'' == raw: # that's a closed socket in fact # using select() to catch readable sockets will also catch closed # sockets (closed by the client). But theses scokets will now # always return an empty string content. You cannot have an empty # string content from a readable socket if it is not a closed # socket. # If you do not close this socket right now, then... you will have # it in the readable sockets as vitam aeternam. self.close_socket() else: self.stream += raw self.requests = Requests().parse(self.stream) # DEBUG self.inmsg(str(self.requests)) if self.requests.count > 0: self._load_testid_and_behavior() if self.behavior.ignore_content_length: # the current response parsing is maybe wrong. self.requests = Requests() self.requests.parse(self.stream, compute_content_length=False) self.inmsg('# Stream after removing Content Length.') self.inmsg(str(self.requests)) if self.requests.count > 0: # Remove from input stream the completed requests self._truncate_input_stream() if self.behavior.echo_query: self.echo_query() # we can send a response, query is fully read self.send_responses() else: self._load_testid_and_behavior(stream_mode=True) if self.behavior.echo_incomplete_query: self.echo_input_stream() def _load_testid_and_behavior(self, stream_mode=False): if (self.test_id is not None and self.detect_test_from_requests(stream_mode)): self.behavior = self.getTestBehavior() else: # this is especially usefull for probe requests self.behavior = self.default_behavior def _truncate_input_stream(self): # self.requests.parsed_idx contains the last index reached with # a complete message self.stream = self.stream[self.requests.parsed_idx:] def echo_query(self): if self.out_queue is not None: self.outmsg('# echoing queries to thread out_queue') self.out_queue.put_nowait(Info(Info.INFO_DATA, id=self.test_id, data=self.requests)) def echo_input_stream(self): if self.out_queue is not None: self.outmsg('# echoing input stream to thread out_queue') self.out_queue.put_nowait(Info(Info.INFO_PARTIAL_DATA, id=self.test_id, data=self.stream)) def detect_test_from_requests(self, stream_mode=False): "Check in raw first line of requests for an httpwookiee test marker." detected = False if stream_mode: import six block = six.text_type(self.stream) else: block = self.requests[0].first_line.raw.decode('utf8') matches = re.match(r'.*httpw=--(.*)--.*', block, re.S) if matches: request_test_id = matches.group(1) if self.test_id == request_test_id: detected = True return detected def send_responses(self): """Prepare the responses stream output. """ position = 1 if self.requests.valid or self.behavior.accept_invalid_request: for request in self.requests: self.send_ok(request=request) if self.requests.count > 1: # add an allowed extra response separator self.output += b"\r\n" position = position + 1 if (self.behavior.add_wookiee_response and position == self.behavior.wookiee_stream_position): self.send_wookiee() # add an allowed extra response separator self.output += b"\r\n" # TODO: behavior timer between wookiee and responses? else: for request in self.requests: if request.valid: self.send_ok(request=request) if self.requests.count > 1: # add an allowed extra response separator self.output += b"\r\n" else: # even if asked to keep conn alive on errors, we cannot # keep a conn alive after an http/0.9 request # every incoming data is just crap from 1st query close = ((request.http09) or not(self.behavior.keep_alive_on_error)) self.send_400(headers=not(request.http09), close=close) if close: break position = position + 1 if (self.behavior.add_wookiee_response and position == self.behavior.wookiee_stream_position): self.send_wookiee() # add an allowed extra response separator self.output += b"\r\n" def send_ok(self, headers=True, close=False, request=None): if request is not None: wlocation = self.config.get('BACKEND_WOOKIEE_LOCATION') # add support for proxies misconfigured, with no prefix path # support : TODO: remove prewlocation = '{0}{1}'.format( self.config.get('BACKEND_LOCATION_PREFIX'), self.config.get('BACKEND_WOOKIEE_LOCATION')) if (request.first_line.location == wlocation or request.first_line.location == prewlocation): return self.send_wookiee() body = b"Hello, World!\r\nIt works!\r\n" if self.behavior.alt_content: body += self.config.get( 'SERVER_NON_DEFAULT_LOCATION_CONTENT').encode('utf8') else: body += self.config.get( 'SERVER_DEFAULT_LOCATION_CONTENT').encode('utf8') if headers: self.output += b"HTTP/1.1 200 OK\r\n" self.output += b"Content-Length: " self.output += str(len(body)).encode('ascii') self.output += b"\r\n" self.output += b"Content-Type: text/html; charset=utf-8\r\n" if close: self.output += b"Connection: Close\r\n" else: self.output += b"Connection: keep-alive\r\n" self.output += b"\r\n" self.output += body if close: self.keepalive = False def send_400(self, headers=True, close=True): if headers: self.output += b"HTTP/1.1 400 Bad Request\r\n" self.output += b"Content-Type: text/html; charset=utf-8\r\n" if close: self.output += b"Connection: Close\r\n" else: self.output += b"Connection: keep-alive\r\n" self.output += b"Content-Length: 24\r\n" self.output += b"\r\n" if close: self.keepalive = False self.output += b"400, Bad Request. GFY!\r\n" def send_wookiee(self, headers=True, close=False): wookiee = b"""<html><body>Wookiee !<hr/><pre> . ``.--::-.` // // . || || . . . `-+hdmNNNNNmdys/. |||. || ||| . ||// || . .:sdNMMMMMMMMMMMMMNdo:`` ||| ||| ||| //]] //]] || [[ /||]/||] :dMMMMMMMMMMMMMNNMNmNho:-:`|||| ||||||| |||| |||| [[|||[ |[ . +mMMMMMNmNNNMMNydMh+ydo:../o ||| ||| [[// [[// || [[||[[//[[// `+MMMMMMMMmyddNdh/No/hdhssys+o+. . oNMMMMMMMMNs/ymdsso-yd/::/yhdds/` . -NMMMNNNMMNNh-oNmhy:hs:..```.-/ss/. . . `sMMMMNNhymNNm:+mmd/yd+:--:/oshdys-. + -mMMNNdhdmhyhNs/mmy+mmyyy+shdo/-.... +MMmddmmNNNmdmdommyyMmho:shs/:-.````.:` . +NMNNdyyysdmmNNmMNdmMm:+dy/:-::-..-../: . . `yNNmmdddmdysdmmMMMNMMsody/+/-:/+//.```.- :h+:/+syhdmNNmdhmMdNMMmmhsosyddhyo+o/.` .` `/+/sddddmdmNNmMNmNh+ymdo/yNMMNhso++`-``` . `/hhmhyhdNMdho+NMmdho/oyhdymMMmy+/:s+.` . . . .sNNNh+smMMMMMMdymNMNms/ohdmdhhyo+ossy: . + . .sNNNddmdmNNMMdymMNNhhNmo/oo+/-/hyyhhoo`` `ohdMMNmso+sNMdNMMMMMMMmyss+--+o::hNNs/.s- . /ohMMNds-+dmhymmNmNMNho/odmddyyd:omdoy+s- . `::dNNNd+/dNNMNmhNdhdyhhhhhhhNMyhs/y/s+:+. . `/mhdmdshdMNmm++yoooohys+/hmNMoydmo`-s+:` . smymNdyooNNNNddhddyysys+hmydMy:hho- sm.``/ooo:. `hhNNmdo/hmhhmmNmNNmh/ymd+:ohMNyoyy+`sm`- .hNMNs. `-+:- . ``.-:/mdMNmh++dNddddh+hmod+/ohdy/oymNmmdy:oN-s.::sNy--ossho:`..` `-+hdmNMdNmMmmhoodNshmNmommsyNs//ymmdyohMMMmo+m+Mh:soms/mMMm/`---`+yo. hNMNmmMMmNdMNmmyyddsshyddhydodmhhso+hmd+mNmyo:hdMm-yNMMNMMNs.:h::sdMNo: mMmdmMMMNmmdmNhmmhsy+yyhNy+my+Nhhy+:/sNohdshy`ydN+ `sMMMMNNdmmNdNMmhho+/` MMMMMMMMMmdmhmMNmho::hyhm+:hssm+yNs:/ddshsdoo.yho+./mMMm/-+hNMMMMMMNdoo+o. MMMMMMMMMNmddyNMd+-.+hsmy-:hohh:mm//shsdoyM+oydsydydmmm- ./-sMMMMMMMMms/oo` MMMMMMMNMMNymmNmo/:-:+dms:ooshshNs+yh/mhmMNNymmyMMMMMMNo+ho/mMMMMMMMMNms/h: MMMMMMNMMMddNMNs+/-/ssdmyosodydMdohNsoNNMMMMMy-:dMMMMMMMMMdMMMMMMMNMMMdys+/: MMMMNmNMMNNNMMMdsosoomNyhdshymNNosNdyyhmMMMMy` -mmhmdmNMMMMMMMMMMNmNMMNmssoo. MMMMmNMMMNMNMMMNshyoNMMNMNyyNMMNhyMdhNMNMMMdo`:mMMMo` -hMMMMMMMMMMNmMMmmm/:ho MMMNmMMMMMMMMMMdyNsdNMMMMMNdmMMMmsNMMMMMMMMmmNMNNN+`:.-hMMMMMMMMMMdmNMNdMms/d/ MMMNMMMMMMNMMMMNhdmdMMMMMMMNNNMMNydNMMMMMMMMMMMMmy.s+-hMMMMMMMMMMMmhNMMdNMmyy+` </pre></html></body>""" if headers: self.output += b"HTTP/1.1 200 OK\r\n" self.output += b"Content-Length: " self.output += str(len(wookiee)).encode('ascii') self.output += b"\r\n" self.output += b"Content-Type: text/html; charset=utf-8\r\n" self.output += b"X-Wookiee: True\r\n" if close: self.output += b"Connection: Close\r\n" else: self.output += b"Connection: keep-alive\r\n" self.output += b"\r\n" if close: self.keepalive = False self.output += wookiee
def read_socket(self): if not self._sock_accept_reads: # This is for sockets that we decided to cut readings from. # like after a 0.9 message raw = b'' else: try: raw = self._sock.recv(self.config.getint( 'BACKEND_SOCK_READ_SIZE')) except ConnectionResetError: # python3 raw = b'' except socket.error as serr: # python2 support if serr.errno != errno.ECONNRESET: # that's another problem raise # [Errno 104] Connection reset by peer raw = b'' self.inmsg(str(raw)) if b'' == raw: # that's a closed socket in fact # using select() to catch readable sockets will also catch closed # sockets (closed by the client). But theses scokets will now # always return an empty string content. You cannot have an empty # string content from a readable socket if it is not a closed # socket. # If you do not close this socket right now, then... you will have # it in the readable sockets as vitam aeternam. self.close_socket() else: self.stream += raw self.requests = Requests().parse(self.stream) # DEBUG self.inmsg(str(self.requests)) if self.requests.count > 0: self._load_testid_and_behavior() if self.behavior.ignore_content_length: # the current response parsing is maybe wrong. self.requests = Requests() self.requests.parse(self.stream, compute_content_length=False) self.inmsg('# Stream after removing Content Length.') self.inmsg(str(self.requests)) if self.requests.count > 0: # Remove from input stream the completed requests self._truncate_input_stream() if self.behavior.echo_query: self.echo_query() # we can send a response, query is fully read self.send_responses() else: self._load_testid_and_behavior(stream_mode=True) if self.behavior.echo_incomplete_query: self.echo_input_stream()
def test_request_bad_chunks(self): "Test chunks output" request = (b"GET /foo HTTP/1.0\r\n" b"Host: example.com\r\n" b"Transfer-Encoding: chunked\r\n" b"\r\n" b"000000008\r\n" b"12345678\r\n" b"04\r\n" b"abcdefghij\r\n" b"5\r\n" b"abcde\r\n" b"1; ZORG\r\n" b"Z\r\n" b"0\r\n" b"\r\n") req = Requests().parse(request) obtained = str(req).split(u'\n') if sys.version_info[0] < 3: # python2 raw8 = (u"**(raw):000000008\\r\\n**" u"**BAD CHUNK < Bad chunk size;>**") else: raw8 = (u"**(raw):b'000000008\\r\\n'**" u"**BAD CHUNK < Bad chunk size;>**") should = [ u'-1 Requests-', u'---', (u'****BAD Request < Has bad Chunk; ' 'Has extra Chunk data;>****'), u' [Req. 1st line]', u'[GET]<SP> [/foo]<SP> HTTP/[1][.][0] [[CR][LF]]', u' [Req. Headers]', u'[HOST] [:]<SP> [example.com] [[CR][LF]]', u'[TRANSFER-ENCODING] [:]<SP> [chunked] [[CR][LF]]', u' [Req. Chunks] (5)', raw8, u'[08 (8)] [[CR][LF]]', u'[04 (4)] [[CR][LF]]', u'[05 (5)] [[CR][LF]]', u'[01 (1)] ;[ ZORG] [[CR][LF]]', u'[LAST CHUNK] [0 (0)] [[CR][LF]]', u' [Req. Body] (size 18)' ] if sys.version_info[0] < 3: # python2 should.append(u'12345678abcdabcdeZ') else: should.append(u"b'12345678abcdabcdeZ'"), should.append(u' ++++++++++++++++++++++++++++++++++++++') should.append(u'') should.append(u'---') self.assertEqual(should, obtained) # 2nd set request = (b"GET /bar HTTP/1.0\r\n" b"Host: example.com\r\n" b"Transfer-Encoding: chunked\r\n" b"\r\n" b" 8\r\n" b"12345678\r\n" b"0004\r\n" b"abcd\r\n" b"6\n" b"abcdef\n" b"0\r\n" b"\r\n") if sys.version_info[0] < 3: # python2 raw8 = (u'**(raw): 8\\r\\n**' u'**BAD CHUNK < Bad chunk start;>**') raw6 = (u"**(raw):6\\n****BAD CHUNK < " u"Line end is LF and not CRLF;>**") else: raw8 = (u'**(raw):b\' 8\\r\\n\'**' u'**BAD CHUNK < Bad chunk start;>**') raw6 = (u"**(raw):b'6\\n'****BAD CHUNK < " u"Line end is LF and not CRLF;>**") req = Requests().parse(request) obtained = str(req).split(u'\n') should = [ u'-1 Requests-', u'---', (u'****BAD Request < Has bad Chunk; ' u'Has extra Chunk data;>****'), u' [Req. 1st line]', u'[GET]<SP> [/bar]<SP> HTTP/[1][.][0] [[CR][LF]]', u' [Req. Headers]', u'[HOST] [:]<SP> [example.com] [[CR][LF]]', u'[TRANSFER-ENCODING] [:]<SP> [chunked] [[CR][LF]]', u' [Req. Chunks] (4)', raw8, u'[08 (8)] [[CR][LF]]', u'[04 (4)] [[CR][LF]]', raw6, u'[06 (6)] [[LF]]', u'[LAST CHUNK] [0 (0)] [[CR][LF]]', u' [Req. Body] (size 18)' ] if sys.version_info[0] < 3: # python2 should.append(u'12345678abcdabcdef') else: should.append(u"b'12345678abcdabcdef'"), should.append(u' ++++++++++++++++++++++++++++++++++++++') should.append(u'') should.append(u'---') self.assertEqual(should, obtained)
def test_request_bad_headers(self): "Test some invalid headers analysis and messages" request = (b"GET /foo HTTP/1.0\r\n" b" H2: v2\r\n" b" H3: v3\r\n" b"Host: example.com\r\n" b"Header1: value1\r\n" b"\x07Foo: Bar\rB\r\n" b"Foo2: Bar\r\rB\r\n" b": zog1\r\n" b"Zog2 Zog:zog \r\n" b"Zog2b\t\r Zog:zog \r\n" b"Zog2c\t \r :zog \r\n" b"Zog3 : zog\r\n" b"Zog4: zog \r\n" b"Zog5\t:zog \r\n" b"Zog6:\tzog \r\n" b"Zog7:zog\t\r\n" b"Zo\0g8: zog \r\n" b"Zog9:\0zog\r\n" b"Zog10:zog\0\r\n" b"Zog11:zog\r\r\n" b"Zog12:zog\n" b"\r\n") req = Requests().parse(request) obtained = str(req).split(u'\n') should = [(u'******INVALID Requests STREAM ' u'< Has invalid Message;>******'), u'-1 Requests-', u'---', (u'****INVALID Request <' u' Has first header in the optional folding format;' u' Has invalid Header;>****'), u' [Req. 1st line]', u'[GET]<SP> [/foo]<SP> HTTP/[1][.][0] [[CR][LF]]', u' [Req. Headers]', u'**BAD HEADER < Optional Multiline Header detected;>**', u'<SP>[] []<SP> [H2:<SP>v2] [[CR][LF]]', u'**BAD HEADER < Optional Multiline Header detected;>**', u'<SP>[] []<SP> [H3:<SP>v3] [[CR][LF]]', u'[HOST] [:]<SP> [example.com] [[CR][LF]]', u'[HEADER1] [:]<SP> [value1] [[CR][LF]]', (u'**INVALID HEADER < Bad space separator;' u' Invalid character in header name;>**'), u'[<Err>FOO] [:]<SP> [Bar<BS>B] [[CR][LF]]', (u'**BAD HEADER < Bad space separator;' u' Multiple CR detected;>**'), u'[FOO2] [:]<SP> [Bar<BS><BS>B] [[CR][LF]]', u'**INVALID HEADER < Empty header name;>**', u'[] [:]<SP> [zog1] [[CR][LF]]', u'**BAD HEADER < Invalid character in header name; ' u'Space in header suffix;>**', u'[ZOG2<ErrSP>ZOG] [:] [zog] <SP>[[CR][LF]]', u'**BAD HEADER < Bad space separator; ' u'Invalid character in header name; ' u'Space in header suffix;>**', u'[ZOG2B<BS><BS><ErrSP>ZOG] [:] [zog] <SP>[[CR][LF]]', u'**INVALID HEADER < Bad space separator; ' u'Invalid character in header name; ' u'Space before separator; ' u'Space in header suffix;>**', u'[ZOG2C] <BS><ErrSP><BS><ErrSP><ErrSP>[:]' u' [zog] <SP>[[CR][LF]]', u'**INVALID HEADER < Invalid character in header name; ' u'Space before separator;>**', u'[ZOG3] <ErrSP>[:]<SP> [zog] [[CR][LF]]', u'**BAD HEADER < Space in header suffix;>**', u'[ZOG4] [:]<SP> [zog] <SP>[[CR][LF]]', (u'**INVALID HEADER < Bad space separator;' u' Space before separator; Space in header suffix;>**'), u'[ZOG5] <BS>[:] [zog] <SP>[[CR][LF]]', (u'**BAD HEADER < Bad space separator;' u' Space in header suffix;>**'), u'[ZOG6] [:]<BS> [zog] <SP>[[CR][LF]]', (u'**BAD HEADER < Space in header suffix;>**'), u'[ZOG7] [:] [zog] <SP>[[CR][LF]]', (u'**INVALID HEADER < Invalid character in header name;' u' Space in header suffix;>**'), u'[ZO<Err>G8] [:]<SP> [zog] <SP>[[CR][LF]]', u'[ZOG9] [:] [\x00zog] [[CR][LF]]', u'[ZOG10] [:] [zog\x00] [[CR][LF]]', u'**BAD HEADER < Multiple CR detected;>**', u'[ZOG11] [:] [zog] [[CR][CR][LF]]', u'**BAD HEADER < Line end is LF and not CRLF;>**', u'[ZOG12] [:] [zog] [[LF]]', u' [Req. Body] (size 0)'] if sys.version_info[0] < 3: # python2 should.append(u'') else: should.append(u"b''"), should.append(u' ++++++++++++++++++++++++++++++++++++++') should.append(u'') should.append(u'---') self.assertEqual(should, obtained)
def test_request_absolute_first_line(self): "Test absolute uris in first lines." # regular absolute domain request = (b"GET http://example.com/foo HTTP/1.1\r\n" b"\r\n") req = Requests().parse(request) obtained = str(req).split(u'\n') should = [ u'-1 Requests-', u'---', u' [Req. 1st line]', (u'[GET]<SP> <[http://][example.com]>[/foo]<SP> ' u'HTTP/[1][.][1] [[CR][LF]]'), u' [Req. Headers]', u' [Req. Body] (size 0)' ] if sys.version_info[0] < 3: should.append(u''), else: should.append(u"b''"), should.append(u' ++++++++++++++++++++++++++++++++++++++') should.append(u'') should.append(u'---') self.assertEqual(should, obtained) # absolute domain: empty domain (with https) request = (b"GET https:// HTTP/1.1\r\n" b"\r\n") req = Requests().parse(request) obtained = str(req).split(u'\n') should = [(u'******INVALID Requests STREAM <' u' Has invalid Message;>******'), u'-1 Requests-', u'---', u'****INVALID Request < Bad First line in Request;>****', u' [Req. 1st line]'] should.append((u'**INVALID FIRST LINE < Empty domain in absolute uri;' u' Empty location;>**')) should.append((u'[GET]<SP> <[https://][<Err>]>[<Err>]<SP> ' u'HTTP/[1][.][1] [[CR][LF]]')) should.append(u' [Req. Headers]') should.append(u' [Req. Body] (size 0)') if sys.version_info[0] < 3: should.append(u'') else: should.append(u"b''"), should.append(u' ++++++++++++++++++++++++++++++++++++++') should.append(u'') should.append(u'---') self.assertEqual(should, obtained) # absolute domain: empty domain v2, with 0.9 request = (b"GET http:///\r\n") req = Requests().parse(request) obtained = str(req).split(u'\n') should = [(u'******INVALID Requests STREAM <' u' Has invalid Message;>******'), u'-1 Requests-', u'---', u'****INVALID Request < Bad First line in Request;>****', u' [Req. 1st line]'] if sys.version_info[0] < 3: should.append(u'**(raw):GET http:///\r') should.append(u"**") else: should.append(u"**(raw):b'GET http:///\\r\\n'**") should.append((u'**INVALID FIRST LINE < Empty domain in absolute uri;' u' Maybe an HTTP/0.9 request;>**')) should.append((u'[GET]<SP> <[http://][<Err>]>[/] ' u'HTTP/[0][.][9] [[CR][LF]]')) should.append(u' [Req. Headers]') should.append(u' [Req. Body] (size 0)') if sys.version_info[0] < 3: should.append(u'') else: should.append(u"b''"), should.append(u' ++++++++++++++++++++++++++++++++++++++') should.append(u'') should.append(u'---') self.assertEqual(should, obtained) # absolute domain: bad chars request = (b"GET http://-example\x0e.com/bar HTTP/1.1\r\n" b"\r\n") req = Requests().parse(request) obtained = str(req).split(u'\n') should = [(u'******INVALID Requests STREAM <' u' Has invalid Message;>******'), u'-1 Requests-', u'---', u'****INVALID Request < Bad First line in Request;>****', u' [Req. 1st line]'] should.append((u'**INVALID FIRST LINE < Bad character in domain;' u' Message should be Rejected;>**')) should.append((u'[GET]<SP> <[http://][<Err>example<Err>.com]>' u'[/bar]<SP> HTTP/[1][.][1] [[CR][LF]]')) should.append(u' [Req. Headers]') should.append(u' [Req. Body] (size 0)') if sys.version_info[0] < 3: should.append(u'') else: should.append(u"b''"), should.append(u' ++++++++++++++++++++++++++++++++++++++') should.append(u'') should.append(u'---') self.assertEqual(should, obtained)