socket read/write timeout
This commit is contained in:
		
							parent
							
								
									8675ff40f3
								
							
						
					
					
						commit
						03193de6d0
					
				| @ -619,9 +619,9 @@ def get_sects(): | ||||
| 
 | ||||
|             \033[32macid\033[0m = extremely safe but slow; the old default. Should never lose any data no matter what | ||||
| 
 | ||||
|             \033[32mswal\033[0m = 2.4x faster uploads yet 99.9%% as safe -- theoretical chance of losing metadata for the ~200 most recently uploaded files if there's a power-loss or your OS crashes | ||||
|             \033[32mswal\033[0m = 2.4x faster uploads yet 99.9% as safe -- theoretical chance of losing metadata for the ~200 most recently uploaded files if there's a power-loss or your OS crashes | ||||
| 
 | ||||
|             \033[32mwal\033[0m = another 21x faster on HDDs yet 90%% as safe; same pitfall as \033[33mswal\033[0m except more likely | ||||
|             \033[32mwal\033[0m = another 21x faster on HDDs yet 90% as safe; same pitfall as \033[33mswal\033[0m except more likely | ||||
| 
 | ||||
|             \033[32myolo\033[0m = another 1.5x faster, and removes the occasional sudden upload-pause while the disk syncs, but now you're at risk of losing the entire database in a powerloss / OS-crash | ||||
| 
 | ||||
| @ -710,6 +710,8 @@ def add_network(ap): | ||||
|         ap2.add_argument("--reuseaddr", action="store_true", help="set reuseaddr on listening sockets on windows; allows rapid restart of copyparty at the expense of being able to accidentally start multiple instances") | ||||
|     else: | ||||
|         ap2.add_argument("--freebind", action="store_true", help="allow listening on IPs which do not yet exist, for example if the network interfaces haven't finished going up. Only makes sense for IPs other than '0.0.0.0', '127.0.0.1', '::', and '::1'. May require running as root (unless net.ipv6.ip_nonlocal_bind)") | ||||
|     ap2.add_argument("--s-thead", metavar="SEC", type=int, default=120, help="socket timeout (read request header)") | ||||
|     ap2.add_argument("--s-tbody", metavar="SEC", type=float, default=186, help="socket timeout (read/write request/response bodies). Use 60 on fast servers (default is extremely safe). Disable with 0 if reverse-proxied for a 2%% speed boost") | ||||
|     ap2.add_argument("--s-wr-sz", metavar="B", type=int, default=256*1024, help="socket write size in bytes") | ||||
|     ap2.add_argument("--s-wr-slp", metavar="SEC", type=float, default=0, help="debug: socket write delay in seconds") | ||||
|     ap2.add_argument("--rsp-slp", metavar="SEC", type=float, default=0, help="debug: response delay in seconds") | ||||
|  | ||||
| @ -219,7 +219,7 @@ class HttpCli(object): | ||||
| 
 | ||||
|         try: | ||||
|             self.s.settimeout(2) | ||||
|             headerlines = read_header(self.sr) | ||||
|             headerlines = read_header(self.sr, self.args.s_thead, self.args.s_thead) | ||||
|             self.in_hdr_recv = False | ||||
|             if not headerlines: | ||||
|                 return False | ||||
| @ -416,6 +416,8 @@ class HttpCli(object): | ||||
|             self.can_upget, | ||||
|         ) = self.asrv.vfs.can_access(self.vpath, self.uname) | ||||
| 
 | ||||
|         self.s.settimeout(self.args.s_tbody or None) | ||||
| 
 | ||||
|         try: | ||||
|             cors_k = self._cors() | ||||
|             if self.mode in ("GET", "HEAD"): | ||||
| @ -558,7 +560,6 @@ class HttpCli(object): | ||||
| 
 | ||||
|         try: | ||||
|             # best practice to separate headers and body into different packets | ||||
|             self.s.settimeout(None) | ||||
|             self.s.sendall("\r\n".join(response).encode("utf-8") + b"\r\n\r\n") | ||||
|         except: | ||||
|             raise Pebkac(400, "client d/c while replying headers") | ||||
| @ -1206,7 +1207,6 @@ class HttpCli(object): | ||||
| 
 | ||||
|         if self.headers.get("expect", "").lower() == "100-continue": | ||||
|             try: | ||||
|                 self.s.settimeout(None) | ||||
|                 self.s.sendall(b"HTTP/1.1 100 Continue\r\n\r\n") | ||||
|             except: | ||||
|                 raise Pebkac(400, "client d/c before 100 continue") | ||||
| @ -1218,7 +1218,6 @@ class HttpCli(object): | ||||
| 
 | ||||
|         if self.headers.get("expect", "").lower() == "100-continue": | ||||
|             try: | ||||
|                 self.s.settimeout(None) | ||||
|                 self.s.sendall(b"HTTP/1.1 100 Continue\r\n\r\n") | ||||
|             except: | ||||
|                 raise Pebkac(400, "client d/c before 100 continue") | ||||
|  | ||||
| @ -537,7 +537,7 @@ class _Unrecv(object): | ||||
|         self.log = log | ||||
|         self.buf: bytes = b"" | ||||
| 
 | ||||
|     def recv(self, nbytes: int) -> bytes: | ||||
|     def recv(self, nbytes: int, spins: int = 1) -> bytes: | ||||
|         if self.buf: | ||||
|             ret = self.buf[:nbytes] | ||||
|             self.buf = self.buf[nbytes:] | ||||
| @ -548,6 +548,10 @@ class _Unrecv(object): | ||||
|                 ret = self.s.recv(nbytes) | ||||
|                 break | ||||
|             except socket.timeout: | ||||
|                 spins -= 1 | ||||
|                 if spins <= 0: | ||||
|                     ret = b"" | ||||
|                     break | ||||
|                 continue | ||||
|             except: | ||||
|                 ret = b"" | ||||
| @ -590,7 +594,7 @@ class _LUnrecv(object): | ||||
|         self.log = log | ||||
|         self.buf = b"" | ||||
| 
 | ||||
|     def recv(self, nbytes: int) -> bytes: | ||||
|     def recv(self, nbytes: int, spins: int) -> bytes: | ||||
|         if self.buf: | ||||
|             ret = self.buf[:nbytes] | ||||
|             self.buf = self.buf[nbytes:] | ||||
| @ -1292,7 +1296,7 @@ class MultipartParser(object): | ||||
|         rfc1341/rfc1521/rfc2047/rfc2231/rfc2388/rfc6266/the-real-world | ||||
|         (only the fallback non-js uploader relies on these filenames) | ||||
|         """ | ||||
|         for ln in read_header(self.sr): | ||||
|         for ln in read_header(self.sr, 2, 2592000): | ||||
|             self.log(ln) | ||||
| 
 | ||||
|             m = self.re_ctype.match(ln) | ||||
| @ -1492,15 +1496,15 @@ def get_boundary(headers: dict[str, str]) -> str: | ||||
|     return m.group(2) | ||||
| 
 | ||||
| 
 | ||||
| def read_header(sr: Unrecv) -> list[str]: | ||||
| def read_header(sr: Unrecv, t_idle: int, t_tot: int) -> list[str]: | ||||
|     t0 = time.time() | ||||
|     ret = b"" | ||||
|     while True: | ||||
|         if time.time() - t0 > 120: | ||||
|         if time.time() - t0 >= t_tot: | ||||
|             return [] | ||||
| 
 | ||||
|         try: | ||||
|             ret += sr.recv(1024) | ||||
|             ret += sr.recv(1024, t_idle // 2) | ||||
|         except: | ||||
|             if not ret: | ||||
|                 return [] | ||||
|  | ||||
| @ -107,6 +107,9 @@ class Cfg(Namespace): | ||||
|         ex = "css_browser hist js_browser no_forget no_hash no_idx" | ||||
|         ka.update(**{k: None for k in ex.split()}) | ||||
| 
 | ||||
|         ex = "s_thead s_tbody" | ||||
|         ka.update(**{k: 9 for k in ex.split()}) | ||||
| 
 | ||||
|         ex = "df loris re_maxage rproxy rsp_jtr rsp_slp s_wr_slp theme themes turbo" | ||||
|         ka.update(**{k: 0 for k in ex.split()}) | ||||
| 
 | ||||
|  | ||||
		Loading…
	
		Reference in New Issue
	
	Block a user
	 ed
						ed