This commit is contained in:
恍兮惚兮 2024-07-08 20:30:14 +08:00
parent 0657cfc6b7
commit 220b8be23c
5 changed files with 46 additions and 54 deletions

View File

@ -154,8 +154,10 @@ class CURLoption(c_int):
CURLOPT_COOKIEFILE = CURLOPTTYPE_STRINGPOINT + 31 CURLOPT_COOKIEFILE = CURLOPTTYPE_STRINGPOINT + 31
CURLOPT_CUSTOMREQUEST = CURLOPTTYPE_STRINGPOINT + 36 CURLOPT_CUSTOMREQUEST = CURLOPTTYPE_STRINGPOINT + 36
CURLOPT_POST = CURLOPTTYPE_LONG + 47 CURLOPT_POST = CURLOPTTYPE_LONG + 47
CURLOPT_FOLLOWLOCATION = CURLOPTTYPE_LONG + 52
CURLOPT_POSTFIELDSIZE = CURLOPTTYPE_LONG + 60 CURLOPT_POSTFIELDSIZE = CURLOPTTYPE_LONG + 60
CURLOPT_SSL_VERIFYPEER = CURLOPTTYPE_LONG + 64 CURLOPT_SSL_VERIFYPEER = CURLOPTTYPE_LONG + 64
CURLOPT_MAXREDIRS = CURLOPTTYPE_LONG + 68
CURLOPT_HEADERFUNCTION = CURLOPTTYPE_FUNCTIONPOINT + 79 CURLOPT_HEADERFUNCTION = CURLOPTTYPE_FUNCTIONPOINT + 79
CURLOPT_HTTPGET = CURLOPTTYPE_LONG + 80 CURLOPT_HTTPGET = CURLOPTTYPE_LONG + 80
CURLOPT_SSL_VERIFYHOST = CURLOPTTYPE_LONG + 81 CURLOPT_SSL_VERIFYHOST = CURLOPTTYPE_LONG + 81

View File

@ -86,6 +86,11 @@ class Session(Sessionbase):
self.last_error = curl_easy_perform(curl) self.last_error = curl_easy_perform(curl)
self.raise_for_status() self.raise_for_status()
def _set_allow_redirects(self, curl, allow_redirects):
curl_easy_setopt(curl, CURLoption.CURLOPT_FOLLOWLOCATION, int(allow_redirects))
# curl_easy_setopt(curl, CURLoption.CURLOPT_MAXREDIRS, 100) #默认50够了
@ExceptionFilter @ExceptionFilter
def request_impl( def request_impl(
self, self,
@ -103,6 +108,7 @@ class Session(Sessionbase):
stream, stream,
verify, verify,
timeout, timeout,
allow_redirects,
): ):
curl = AutoCURLHandle(curl_easy_init()) curl = AutoCURLHandle(curl_easy_init())
curl_easy_setopt(curl, CURLoption.CURLOPT_COOKIEJAR, "") curl_easy_setopt(curl, CURLoption.CURLOPT_COOKIEJAR, "")
@ -146,6 +152,7 @@ class Session(Sessionbase):
self._set_verify(curl, verify) self._set_verify(curl, verify)
self._set_proxy(curl, proxy) self._set_proxy(curl, proxy)
self._set_allow_redirects(curl, allow_redirects)
if datalen: if datalen:
curl_easy_setopt(curl, CURLoption.CURLOPT_POSTFIELDS, dataptr) curl_easy_setopt(curl, CURLoption.CURLOPT_POSTFIELDS, dataptr)
curl_easy_setopt(curl, CURLoption.CURLOPT_POSTFIELDSIZE, datalen) curl_easy_setopt(curl, CURLoption.CURLOPT_POSTFIELDSIZE, datalen)
@ -154,7 +161,9 @@ class Session(Sessionbase):
resp.keeprefs.append(curl) resp.keeprefs.append(curl)
if stream: if stream:
def WriteMemoryCallback(queue, contents, size, nmemb, userp): def WriteMemoryCallback(headerqueue, queue, contents, size, nmemb, userp):
if headerqueue:
headerqueue.put(0)
realsize = size * nmemb realsize = size * nmemb
queue.put(cast(contents, POINTER(c_char))[:realsize]) queue.put(cast(contents, POINTER(c_char))[:realsize])
return realsize return realsize
@ -162,9 +171,11 @@ class Session(Sessionbase):
_content = [] _content = []
_headers = [] _headers = []
headerqueue = queue.Queue() headerqueue = queue.Queue()
keepref1 = WRITEFUNCTION(functools.partial(WriteMemoryCallback, resp.queue)) keepref1 = WRITEFUNCTION(
functools.partial(WriteMemoryCallback, headerqueue, resp.queue)
)
keepref2 = WRITEFUNCTION( keepref2 = WRITEFUNCTION(
functools.partial(WriteMemoryCallback, headerqueue) functools.partial(WriteMemoryCallback, None, headerqueue)
) )
curl_easy_setopt( curl_easy_setopt(
curl, curl,
@ -185,7 +196,7 @@ class Session(Sessionbase):
self._perform(curl) self._perform(curl)
except: except:
print_exc() print_exc()
headerqueue.put(None) headerqueue.put(1)
error = True error = True
resp.queue.put(None) resp.queue.put(None)
if error: if error:
@ -195,27 +206,16 @@ class Session(Sessionbase):
threading.Thread(target=___perform, daemon=True).start() threading.Thread(target=___perform, daemon=True).start()
headerb = "" headerb = ""
cnt = 1
while True: while True:
_headerb = headerqueue.get() _headerb = headerqueue.get()
if _headerb is None: if _headerb == 0:
break
elif _headerb == 1:
self.raise_for_status() self.raise_for_status()
_headerb = _headerb.decode("utf8") _headerb = _headerb.decode("utf8")
if _headerb.startswith("HTTP/"):
if _headerb.endswith(
"200 Connection established\r\n"
): # HTTP/1.1 200 Connection established\r\n
cnt += 1
elif _headerb == "\r\n":
cnt -= 1
if cnt == 0:
break
else:
# 有proxy时proxy也有可能有header.
headerb = "" headerb = ""
else:
headerb += _headerb headerb += _headerb
resp.headers = self._update_header_cookie(headerb) resp.headers = self._update_header_cookie(headerb)
resp.status_code = self._getStatusCode(curl) resp.status_code = self._getStatusCode(curl)
else: else:

View File

@ -313,36 +313,7 @@ class Sessionbase:
stream, stream,
verify, verify,
timeout, timeout,
) allow_redirects,
while allow_redirects and (
_.status_code == 301 or _.status_code == 302 or _.status_code == 307
):
location = _.headers["Location"]
if location.startswith("/"): # vndb
url = url = scheme + "://" + server + location
param = location
elif location.startswith(
"http"
): # https://api.github.com/repos/XXX/XXX/zipball
scheme, server, port, param, url = self._parseurl(location, None)
else:
raise Exception("redirect {}: {}".format(_.status_code, location))
_ = self.request_impl(
method,
scheme,
server,
port,
param,
url,
headers,
cookies,
dataptr,
datalen,
proxy,
stream,
verify,
timeout,
) )
return _ return _

View File

@ -118,11 +118,23 @@ class Session(Sessionbase):
if proxy: if proxy:
winhttpsetproxy(hsess, proxy) winhttpsetproxy(hsess, proxy)
def _set_verify(self, curl, verify): def _set_verify(self, hRequest, verify):
if verify == False: if verify == False:
dwFlags = DWORD(SECURITY_FLAG_IGNORE_ALL_CERT_ERRORS) dwFlags = DWORD(SECURITY_FLAG_IGNORE_ALL_CERT_ERRORS)
WinHttpSetOption( WinHttpSetOption(
curl, WINHTTP_OPTION_SECURITY_FLAGS, pointer(dwFlags), sizeof(dwFlags) hRequest,
WINHTTP_OPTION_SECURITY_FLAGS,
pointer(dwFlags),
sizeof(dwFlags),
)
def _set_allow_redirects(self, hRequest, allow_redirects):
if allow_redirects:
dwFlags = DWORD(WINHTTP_OPTION_REDIRECT_POLICY_ALWAYS)
else:
dwFlags = DWORD(WINHTTP_OPTION_REDIRECT_POLICY_NEVER)
WinHttpSetOption(
hRequest, WINHTTP_OPTION_REDIRECT_POLICY, pointer(dwFlags), sizeof(dwFlags)
) )
@ExceptionFilter @ExceptionFilter
@ -142,6 +154,7 @@ class Session(Sessionbase):
stream, stream,
verify, verify,
timeout, timeout,
allow_redirects,
): ):
headers = self._parseheader(headers, cookies) headers = self._parseheader(headers, cookies)
flag = WINHTTP_FLAG_SECURE if scheme == "https" else 0 flag = WINHTTP_FLAG_SECURE if scheme == "https" else 0
@ -168,7 +181,7 @@ class Session(Sessionbase):
raise WinhttpException(GetLastError()) raise WinhttpException(GetLastError())
self._set_verify(hRequest, verify) self._set_verify(hRequest, verify)
self._set_proxy(hRequest, proxy) self._set_proxy(hRequest, proxy)
self._set_allow_redirects(hRequest, allow_redirects)
succ = WinHttpSendRequest( succ = WinHttpSendRequest(
hRequest, headers, -1, dataptr, datalen, datalen, None hRequest, headers, -1, dataptr, datalen, datalen, None
) )

View File

@ -2,6 +2,7 @@ from ctypes import windll, POINTER, pointer, Structure, sizeof
from ctypes.wintypes import LPCWSTR, DWORD, LPVOID, WORD, BOOL, LPCVOID, LPWSTR, USHORT from ctypes.wintypes import LPCWSTR, DWORD, LPVOID, WORD, BOOL, LPCVOID, LPWSTR, USHORT
from network.requests_common import NetWorkException from network.requests_common import NetWorkException
class WinhttpException(NetWorkException): class WinhttpException(NetWorkException):
ERROR_INVALID_PARAMETER = 87 ERROR_INVALID_PARAMETER = 87
ERROR_INVALID_OPERATION = 4317 ERROR_INVALID_OPERATION = 4317
@ -225,3 +226,8 @@ WINHTTP_WEB_SOCKET_UTF8_FRAGMENT_BUFFER_TYPE = 3
WINHTTP_WEB_SOCKET_CLOSE_BUFFER_TYPE = 4 WINHTTP_WEB_SOCKET_CLOSE_BUFFER_TYPE = 4
ERROR_SUCCESS = 0 ERROR_SUCCESS = 0
WINHTTP_WEB_SOCKET_SUCCESS_CLOSE_STATUS = 1000 WINHTTP_WEB_SOCKET_SUCCESS_CLOSE_STATUS = 1000
WINHTTP_OPTION_REDIRECT_POLICY = 88
WINHTTP_OPTION_REDIRECT_POLICY_ALWAYS = 2
WINHTTP_OPTION_REDIRECT_POLICY_NEVER = 0