This commit is contained in:
HIllya51 2024-01-10 20:32:14 +08:00
parent d7ebef036a
commit c990426f63
6 changed files with 81 additions and 36 deletions

View File

@ -138,6 +138,7 @@ class CURLoption(c_int):
CURLOPT_COOKIEJAR=CURLOPTTYPE_STRINGPOINT+82
CURLOPT_COOKIESESSION=CURLOPTTYPE_LONG+96
CURLOPT_SHARE=CURLOPTTYPE_OBJECTPOINT+100
CURLOPT_ACCEPT_ENCODING=CURLOPTTYPE_STRINGPOINT+102
CURLOPT_CONNECT_ONLY=CURLOPTTYPE_LONG+141
class CURLINFO(c_int):
CURLINFO_STRING =0x100000

View File

@ -50,8 +50,7 @@ class Session(Sessionbase):
return cast(mem.memory,POINTER(c_char))[:mem.size]
def request_impl(self,
method,scheme,server,port,param,url,headers,cookies,dataptr,datalen,proxy,stream,verify):
headers=self._parseheader(headers,None)#curl对于headers中有cookie且session中也有cookie的情况下不会自动合并而是会有两个cookie键所以不能在header里放cookie
if self._status==0:
curl=self.curl
__=autostatus(self)
@ -65,6 +64,8 @@ class Session(Sessionbase):
if cookies:
cookie=self._parsecookie(cookies)
curl_easy_setopt(curl, CURLoption.CURLOPT_COOKIE, cookie.encode('utf8'));
curl_easy_setopt(curl,CURLoption.CURLOPT_ACCEPT_ENCODING, headers['Accept-Encoding'].encode('utf8'))
curl_easy_setopt(curl,CURLoption.CURLOPT_CUSTOMREQUEST,method.upper().encode('utf8'))
self.last_error=curl_easy_setopt(curl,CURLoption.CURLOPT_URL,url.encode('utf8'))
@ -72,7 +73,7 @@ class Session(Sessionbase):
curl_easy_setopt(curl, CURLoption.CURLOPT_PORT, port )
lheaders=Autoslist()
for _ in headers:
for _ in self._parseheader(headers,None):
lheaders = curl_slist_append(cast(lheaders,POINTER(curl_slist)), _.encode('utf8'));
self.last_error=curl_easy_setopt(curl, CURLoption.CURLOPT_HTTPHEADER, lheaders);
self.raise_for_status()
@ -91,7 +92,7 @@ class Session(Sessionbase):
curl_easy_setopt(curl,CURLoption.CURLOPT_HEADERFUNCTION,winsharedutils.WriteMemoryCallback)
self._perform(curl)
self.content=self._getmembyte(_content)
self.rawdata=self._getmembyte(_content)
self._update_header_cookie(self._getmembyte(_headers).decode('utf8'))

View File

@ -1,8 +1,8 @@
import json,gzip,base64
import json,base64,re
from collections.abc import Callable, Mapping, MutableMapping
from collections import OrderedDict
from urllib.parse import urlencode,urlsplit
from functools import partial,partialmethod
class CaseInsensitiveDict(MutableMapping):
def __init__(self, data=None, **kwargs):
@ -52,11 +52,11 @@ class Sessionbase:
self.UA='Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36'
self.last_error=0
self.status_code=0
self.content=b'{}'
self.rawdata=b'{}'
self.cookies={}
self.dfheaders=CaseInsensitiveDict({
"User-Agent": self.UA,
"Accept-Encoding": 'gzip, deflate',#br
"Accept-Encoding": 'gzip, deflate, br',
"Accept": "*/*",
"Connection": "keep-alive",
})
@ -166,33 +166,34 @@ class Sessionbase:
else:
header[line[:idx]]=line[idx+2:]
return CaseInsensitiveDict(header),cookie
def decompress_impl(self,data,encode):
return data
@property
def text(self):
encode=self.headers.get('Content-Encoding',None)
try:
if encode =='gzip':
self.content=gzip.decompress(self.content)
# elif encode=='br':
# self.content=brotli.decompress(self.content)
return self.content.decode('utf8')
def content(self):
return self.decompress_impl(self.rawdata,self.headers.get('Content-Encoding',None))
@property
def text(self):
try:
return self.content.decode(self.charset)
except:
raise Exception('unenable to decode {}'.format(encode))
raise Exception('unenable to decode with {}'.format(self.charset))
@property
def charset(self):
content_type=self.headers.get('Content-Type','')
m = re.search(r"charset=([\w-]+)", content_type)
charset = m.group(1) if m else "utf-8"
return charset
def json(self):
return json.loads(self.text)
def get(self, url, **kwargs):
return self.request("GET", url, **kwargs)
def post(self, url, **kwargs):
return self.request("POST", url, **kwargs)
def options(self, url, **kwargs):
return self.request("OPTIONS", url, **kwargs)
def request_impl(self,*args):
pass
def request(self,
method, url, params=None, data=None, headers=None,proxies=None, json=None,cookies=None, files=None,
auth=None, timeout=None, allow_redirects=True, hooks=None, stream=None, verify=False, cert=None, ):
headers=CaseInsensitiveDict(headers) if headers else self.dfheaders
headers=CaseInsensitiveDict(headers if headers else {})
headers.update(self.dfheaders)
if auth and isinstance(auth,tuple) and len(auth)==2:
headers['Authorization']="Basic " + ( base64.b64encode(b":".join((auth[0].encode("latin1"), auth[1].encode("latin1")))).strip() ).decode()
@ -204,16 +205,16 @@ class Sessionbase:
_= self.request_impl(method,scheme,server,port,param,url,headers,cookies,dataptr,datalen,proxy,stream,verify)
return _
get=partialmethod(request,"GET")
post=partialmethod(request,"POST")
options=partialmethod(request,"OPTIONS")
Sessionimpl=[Sessionbase]
def request(method, url, **kwargs):
with Sessionimpl[0]() as session:
return session.request(method=method, url=url, **kwargs)
def get(url, params=None, **kwargs):
return request("GET", url, params=params, **kwargs)
def post(url, params=None, **kwargs):
return request("POST", url, params=params, **kwargs)
def options(url, params=None, **kwargs):
return request("OPTIONS", url, params=params, **kwargs)
def session():
with Sessionimpl[0]() as session:
return session
return session
get=partial(request,"GET")
post=partial(request,"POST")
options=partial(request,"OPTIONS")

View File

@ -0,0 +1,19 @@
from ctypes import CDLL,c_size_t,c_void_p,POINTER,pointer,create_string_buffer
import os,platform
dllpath=os.path.abspath(os.path.join('./files/plugins/brotli',['./x64/brotlicommon.dll','./x86/brotlicommon.dll'][platform.architecture()[0]=='32bit']))
_brotli=CDLL(dllpath)
dllpath=os.path.abspath(os.path.join('./files/plugins/brotli',['./x64/brotlidec.dll','./x86/brotlidec.dll'][platform.architecture()[0]=='32bit']))
_brotli=CDLL(dllpath)
BrotliDecoderDecompress=_brotli.BrotliDecoderDecompress
BrotliDecoderDecompress.argtypes=c_size_t,c_void_p,POINTER(c_size_t),c_void_p
def decompress(data):
size=c_size_t(1024)
while 1:
buff=create_string_buffer(size.value)
succ=BrotliDecoderDecompress(len(data),data,pointer(size),buff)
if succ==0:
size=c_size_t(size.value*2)
else:break
return buff.raw[:size.value]

View File

@ -1,6 +1,12 @@
from winhttp import *
from network.requests_common import *
import gzip,zlib
from ctypes import pointer,create_string_buffer
try:
from brotli_dec import decompress
except:
pass
class Session(Sessionbase):
def __init__(self) -> None:
super().__init__()
@ -83,7 +89,7 @@ class Session(Sessionbase):
succ=WinHttpReadData(hRequest,buff,availableSize,pointer(downloadedSize))
if succ==0:raise WinhttpException(GetLastError())
downloadeddata+=buff[:downloadedSize.value]
self.content=downloadeddata
self.rawdata=downloadeddata
#print(self.text)
return self
@ -99,7 +105,20 @@ class Session(Sessionbase):
del self.hconn
break
yield buff[:downloadedSize.value]
def decompress_impl(self,data,encode):
#WINHTTP_OPTION_DECOMPRESSION
#支持gzip和deflateWINHTTP_DECOMPRESSION_FLAG_GZIP|WINHTTP_DECOMPRESSION_FLAG_DEFLATE
#但只支持win8.1+,不支持br
try:
if encode =='gzip':
data=gzip.decompress(data)
elif encode =='deflate':
data=zlib.decompress(data, -zlib.MAX_WBITS)
elif encode=='br':
data=decompress(data)
return data
except:
raise Exception('unenable to decompress {}'.format(encode))
Sessionimpl[0]=Session
if __name__=='__main__':
pass

View File

@ -9,7 +9,9 @@ if x86:
badcdlls= [
'libcurl-x64.dll','libmecab64.dll',
'ocr64.dll',
'winsharedutils64.dll','winrtutils64.dll'
'winsharedutils64.dll','winrtutils64.dll',
r'brotli\x64\brotlicommon.dll',
r'brotli\x64\brotlidec.dll',
]
downlevel=f'C:\Windows\SysWOW64\downlevel'
target='LunaTranslator_x86.zip'
@ -21,7 +23,9 @@ else:
badcdlls= [
'libcurl.dll','libmecab32.dll',
'ocr32.dll',
'winsharedutils32.dll','winrtutils32.dll'
'winsharedutils32.dll','winrtutils32.dll',
r'brotli\x86\brotlicommon.dll',
r'brotli\x86\brotlidec.dll',
]
downlevel=f'C:\Windows\system32\downlevel'
targetdir_in=rf'{targetdir}\LunaTranslator'