1
0
mirror of https://github.com/openSUSE/osc.git synced 2025-01-13 17:16:23 +01:00

Lock cookiejar to prevent unnecessary signature auth

This usually happens when a user runs multiple osc instances
from the command-line in parallel.
This commit is contained in:
Daniel Mach 2022-08-25 15:26:46 +02:00
parent 8ca816755a
commit a4a984ee14

View File

@ -1,5 +1,5 @@
import base64 import base64
import errno import fcntl
import os import os
import re import re
import subprocess import subprocess
@ -415,11 +415,20 @@ class AuthHandlerBase:
class CookieJarAuthHandler(AuthHandlerBase): class CookieJarAuthHandler(AuthHandlerBase):
# Shared among instances, instantiate on first use, key equals too cookiejar path. # Shared among instances, instantiate on first use, key equals to cookiejar path.
COOKIEJARS = {} COOKIEJARS = {}
def __init__(self, cookiejar_path): def __init__(self, cookiejar_path):
self.cookiejar_path = cookiejar_path self.cookiejar_path = cookiejar_path
if self.cookiejar_path in self.COOKIEJARS:
self.cookiejar_lock_path = None
else:
# Cookiejar hasn't been loaded yet, let's lock it to avoid
# doing expensive signature auth in multiple processes.
# This usually happens when a user runs multiple osc instances
# from the command-line in parallel.
self.cookiejar_lock_path = self.cookiejar_path + ".lock"
self.cookiejar_lock_fd = None
@property @property
def _cookiejar(self): def _cookiejar(self):
@ -427,18 +436,37 @@ class CookieJarAuthHandler(AuthHandlerBase):
if not jar: if not jar:
try: try:
os.makedirs(os.path.dirname(self.cookiejar_path), mode=0o700) os.makedirs(os.path.dirname(self.cookiejar_path), mode=0o700)
except OSError as e: except FileExistsError:
if e.errno != errno.EEXIST: pass
raise
jar = http.cookiejar.LWPCookieJar(self.cookiejar_path) jar = http.cookiejar.LWPCookieJar(self.cookiejar_path)
if os.path.isfile(self.cookiejar_path): if os.path.isfile(self.cookiejar_path):
jar.load() jar.load()
self.COOKIEJARS[self.cookiejar_path] = jar self.COOKIEJARS[self.cookiejar_path] = jar
return jar return jar
def _lock(self):
if self.cookiejar_lock_path:
try:
os.makedirs(os.path.dirname(self.cookiejar_lock_path), mode=0o700)
except FileExistsError:
pass
self.cookiejar_lock_fd = open(self.cookiejar_lock_path, "w")
fcntl.flock(self.cookiejar_lock_fd, fcntl.LOCK_EX)
def _unlock(self):
if self.cookiejar_lock_path:
self.cookiejar_lock_path = None
fcntl.flock(self.cookiejar_lock_fd, fcntl.LOCK_UN)
self.cookiejar_lock_fd.close()
def set_request_headers(self, url, request_headers): def set_request_headers(self, url, request_headers):
self._lock()
self._cookiejar.add_cookie_header(MockRequest(url, request_headers)) self._cookiejar.add_cookie_header(MockRequest(url, request_headers))
return bool(request_headers.get_all("cookie", None)) if request_headers.get_all("cookie", None):
# we have a valid cookie already -> unlock immediately
self._unlock()
return True
return False
def set_request_headers_after_401(self, url, request_headers, response): def set_request_headers_after_401(self, url, request_headers, response):
# can't do anything, we have tried setting a cookie already # can't do anything, we have tried setting a cookie already
@ -447,6 +475,7 @@ class CookieJarAuthHandler(AuthHandlerBase):
def process_response(self, url, request_headers, response): def process_response(self, url, request_headers, response):
self._cookiejar.extract_cookies(response, MockRequest(url, response.headers)) self._cookiejar.extract_cookies(response, MockRequest(url, response.headers))
self._cookiejar.save() self._cookiejar.save()
self._unlock()
class BasicAuthHandler(AuthHandlerBase): class BasicAuthHandler(AuthHandlerBase):