From da35c69bc47c6a0e12eb5b94c9d83732d4e6a41a Mon Sep 17 00:00:00 2001 From: Concedo <39025047+LostRuins@users.noreply.github.com> Date: Sun, 7 Jun 2026 22:37:00 +0800 Subject: [PATCH] clean path and strip query params for all http POST routes --- koboldcpp.py | 106 ++++++++++++++++++++++++++------------------------- 1 file changed, 54 insertions(+), 52 deletions(-) diff --git a/koboldcpp.py b/koboldcpp.py index 218283ae1..dd5bc00b6 100644 --- a/koboldcpp.py +++ b/koboldcpp.py @@ -4531,12 +4531,13 @@ class KcppProxyHandler(http.server.BaseHTTPRequestHandler): global global_memory #specifically look for generation requests from completions or chat completions to handle hotswap is_post = self.command.upper() == "POST" - is_completions_path = (self.path.endswith('/v1/completions') or self.path.endswith('/v1/completion') or self.path=='/completions') - is_chat_completions_path = (self.path.endswith('/v1/chat/completions') or self.path=='/chat/completions') + clean_path = self.path.split("?")[0] #for cases where we do not want query params + is_completions_path = (clean_path.endswith('/v1/completions') or clean_path.endswith('/v1/completion') or clean_path=='/completions') + is_chat_completions_path = (clean_path.endswith('/v1/chat/completions') or clean_path=='/chat/completions') #any requests to the following endpoints is capable of waking the server wake_requests = ["/api/extra/generate/stream","/api/extra/tokencount","/api/v1/generate","/sdapi/v1/interrogate","/v1/completions","/v1/chat/completions","/v1/responses","/completions","/chat/completions","/responses","/api/extra/transcribe","/v1/audio/transcriptions","/api/extra/tts","/v1/audio/speech","/api/extra/embeddings","/v1/embeddings","/api/extra/music/prepare","/api/extra/music/generate","/sdapi/v1/txt2img","/sdapi/v1/img2img","/sdapi/v1/upscale"] - is_wake_request = self.path in wake_requests + is_wake_request = clean_path in wake_requests autoswapEnabled = global_memory["autoswapmode"] is not None and global_memory["autoswapmode"] model_switch_pass = False @@ -4592,22 +4593,22 @@ class KcppProxyHandler(http.server.BaseHTTPRequestHandler): imageReqs = ["/sdapi/v1/txt2img", "/sdapi/v1/img2img", "/sdapi/v1/upscale"] # "/sdapi/v1/sd-models", "/sdapi/v1/options", "/sdapi/v1/samplers" swapModeChanged = False - if any(self.path.endswith(e) for e in textReqs) and (global_memory["swapReqType"] is None or global_memory["swapReqType"] != "text"): + if any(clean_path.endswith(e) for e in textReqs) and (global_memory["swapReqType"] is None or global_memory["swapReqType"] != "text"): global_memory["swapReqType"] = "text" swapModeChanged = True - elif any(self.path.endswith(e) for e in sttReqs) and (global_memory["swapReqType"] is None or global_memory["swapReqType"] != "stt"): + elif any(clean_path.endswith(e) for e in sttReqs) and (global_memory["swapReqType"] is None or global_memory["swapReqType"] != "stt"): global_memory["swapReqType"] = "stt" swapModeChanged = True - elif any(self.path.endswith(e) for e in ttsReqs) and (global_memory["swapReqType"] is None or global_memory["swapReqType"] != "tts"): + elif any(clean_path.endswith(e) for e in ttsReqs) and (global_memory["swapReqType"] is None or global_memory["swapReqType"] != "tts"): global_memory["swapReqType"] = "tts" swapModeChanged = True - elif any(self.path.endswith(e) for e in embedReqs) and (global_memory["swapReqType"] is None or global_memory["swapReqType"] != "embed"): + elif any(clean_path.endswith(e) for e in embedReqs) and (global_memory["swapReqType"] is None or global_memory["swapReqType"] != "embed"): global_memory["swapReqType"] = "embed" swapModeChanged = True - elif any(self.path.endswith(e) for e in musicReqs) and (global_memory["swapReqType"] is None or global_memory["swapReqType"] != "music"): + elif any(clean_path.endswith(e) for e in musicReqs) and (global_memory["swapReqType"] is None or global_memory["swapReqType"] != "music"): global_memory["swapReqType"] = "music" swapModeChanged = True - elif any(self.path.endswith(e) for e in imageReqs) and (global_memory["swapReqType"] is None or global_memory["swapReqType"] != "image"): + elif any(clean_path.endswith(e) for e in imageReqs) and (global_memory["swapReqType"] is None or global_memory["swapReqType"] != "image"): global_memory["swapReqType"] = "image" swapModeChanged = True @@ -6070,10 +6071,11 @@ Change Mode
return self.path = self.path.rstrip('/') + clean_path = self.path.split("?")[0] #for cases where we do not want query params response_body = None response_code = 200 - if self.path.endswith('/api/extra/tokencount') or self.path.endswith('/api/extra/tokenize'): + if clean_path.endswith('/api/extra/tokencount') or clean_path.endswith('/api/extra/tokenize'): if not self.secure_endpoint(): return try: @@ -6092,7 +6094,7 @@ Change Mode
response_code = 400 response_body = (json.dumps({"value": -1}).encode()) - elif self.path.endswith('/api/extra/detokenize'): + elif clean_path.endswith('/api/extra/detokenize'): if not self.secure_endpoint(): return try: @@ -6106,7 +6108,7 @@ Change Mode
response_code = 400 response_body = (json.dumps({"result": "","success":False}).encode()) - elif self.path.endswith('/api/extra/json_to_grammar'): + elif clean_path.endswith('/api/extra/json_to_grammar'): if not self.secure_endpoint(): return try: @@ -6121,7 +6123,7 @@ Change Mode
response_code = 400 response_body = (json.dumps({"result": "","success":False}).encode()) - elif self.path.endswith('/api/extra/abort'): + elif clean_path.endswith('/api/extra/abort'): if not self.secure_endpoint(): return multiuserkey = "" @@ -6143,7 +6145,7 @@ Change Mode
else: response_body = (json.dumps({"success": "false", "done":"false"}).encode()) - elif self.path.endswith('/api/extra/generate/check'): + elif clean_path.endswith('/api/extra/generate/check'): if not self.secure_endpoint(): return pendtxtStr = "" @@ -6161,7 +6163,7 @@ Change Mode
pendtxtStr = ctypes.string_at(pendtxt).decode("UTF-8","ignore") response_body = (json.dumps({"results": [{"text": pendtxtStr}]}).encode()) - elif self.path.endswith('/api/extra/last_logprobs'): + elif clean_path.endswith('/api/extra/last_logprobs'): if not self.secure_endpoint(): return logprobsdict = None @@ -6179,7 +6181,7 @@ Change Mode
logprobsdict = parse_last_logprobs(lastlogprobs) response_body = (json.dumps({"logprobs":logprobsdict}).encode()) - elif self.path.endswith('/api/extra/multiplayer/status'): + elif clean_path.endswith('/api/extra/multiplayer/status'): if not self.secure_endpoint(): return if not has_multiplayer: @@ -6198,7 +6200,7 @@ Change Mode
multiplayer_lastactive[sender] = int(time.time()) response_body = (json.dumps({"turn_major":multiplayer_turn_major,"turn_minor":multiplayer_turn_minor,"idle":self.get_multiplayer_idle_state(sender),"data_format":multiplayer_dataformat}).encode()) - elif self.path.endswith('/api/extra/data/list'): + elif clean_path.endswith('/api/extra/data/list'): if not self.secure_endpoint(): return if savedata_obj is None: @@ -6212,7 +6214,7 @@ Change Mode
output.append("") response_body = (json.dumps(output).encode()) - elif self.path.endswith('/api/extra/data/load'): + elif clean_path.endswith('/api/extra/data/load'): if not self.secure_endpoint(): return if savedata_obj is None: @@ -6228,7 +6230,7 @@ Change Mode
else: response_body = (json.dumps({"success":True,"data":savedata_obj[str(loadid)]}).encode()) - elif self.path.endswith('/api/extra/data/save'): + elif clean_path.endswith('/api/extra/data/save'): if not self.secure_endpoint(): return if savedata_obj is None: @@ -6276,7 +6278,7 @@ Change Mode
response_code = 400 response_body = (json.dumps({"success": False, "error":"Submitted story invalid!"}).encode()) - elif self.path.endswith('/api/extra/multiplayer/getstory'): + elif clean_path.endswith('/api/extra/multiplayer/getstory'): if not self.secure_endpoint(): return if not has_multiplayer: @@ -6286,7 +6288,7 @@ Change Mode
else: response_body = multiplayer_story_data_compressed.encode() - elif self.path.endswith('/api/extra/multiplayer/setstory'): + elif clean_path.endswith('/api/extra/multiplayer/setstory'): if not self.secure_endpoint(): return if not has_multiplayer: @@ -6323,7 +6325,7 @@ Change Mode
response_code = 400 response_body = (json.dumps({"success": False, "error":"Submitted story invalid!"}).encode()) - elif self.path.startswith(("/api/extra/websearch")): + elif clean_path.startswith(("/api/extra/websearch")): if not self.secure_endpoint(): return if args.websearch: @@ -6339,7 +6341,7 @@ Change Mode
else: response_body = (json.dumps([]).encode()) - elif self.path.startswith(("/api/admin/reload_config")): + elif clean_path.startswith(("/api/admin/reload_config")): resp = {"success": False} if global_memory and args.admin and args.admindir and os.path.exists(args.admindir) and self.check_header_password(args.adminpassword): targetfile = "" @@ -6375,13 +6377,13 @@ Change Mode
resp = {"success": True} response_body = (json.dumps(resp).encode()) - elif self.path.endswith('/set_tts_settings'): #return dummy response + elif clean_path.endswith('/set_tts_settings'): #return dummy response response_body = (json.dumps({"message": "Settings successfully applied"}).encode()) - elif self.path=="/api/show": #ollama compatible + elif clean_path=="/api/show": #ollama compatible response_body = (json.dumps({"parameters":"temperature 1.0","license":"Ollama Emulation. Running on KoboldCpp","modelfile":"KoboldCpp","capabilities":["completion"],"modified_at":"2025-01-01T01:00:00.0000000+00:00","details":{},"model_info":{}}).encode()) - elif self.path=="/mcp": #simple mcp proxy + elif clean_path=="/mcp": #simple mcp proxy if not self.secure_endpoint(): return try: @@ -6434,7 +6436,7 @@ Change Mode
response_code = 400 response_body = (json.dumps({"error": {"code": -32700, "message": "Parse error"}}).encode()) - elif self.path=="/api/extra/shutdown": + elif clean_path=="/api/extra/shutdown": # if args.singleinstance: client_ip = self.client_address[0] is_local = client_ip in ('127.0.0.1', '::1', 'localhost') @@ -6515,7 +6517,7 @@ Change Mode
use_jinja = args.jinja global_memory["last_active_timestamp"] = datetime.now() global_memory["triggered_sleeping"] = False - if self.path.endswith('/api/admin/check_state'): + if clean_path.endswith('/api/admin/check_state'): if global_memory and args.admin and args.admindir and os.path.exists(args.admindir) and self.check_header_password(args.adminpassword): cur_states = [] for sl in range(savestate_limit): #0,1,2,3 @@ -6527,7 +6529,7 @@ Change Mode
response_body = (json.dumps({"success": True, "old_states":cur_states, "new_state_size":newstate, "new_tokens":newtokencnt}).encode()) else: response_body = (json.dumps({"success": False, "old_states":[], "new_state_size":0, "new_tokens":0}).encode()) - elif self.path.endswith('/api/admin/load_state'): + elif clean_path.endswith('/api/admin/load_state'): if global_memory and savestate_limit>0 and args.admin and args.admindir and os.path.exists(args.admindir) and self.check_header_password(args.adminpassword): targetslot = 0 try: @@ -6542,7 +6544,7 @@ Change Mode
response_body = (json.dumps({"success": result, "new_tokens":tokencnt}).encode()) else: response_body = (json.dumps({"success": False, "new_tokens":0}).encode()) - elif self.path.endswith('/api/admin/save_state'): + elif clean_path.endswith('/api/admin/save_state'): if global_memory and savestate_limit>0 and args.admin and args.admindir and os.path.exists(args.admindir) and self.check_header_password(args.adminpassword): targetslot = 0 try: @@ -6557,30 +6559,30 @@ Change Mode
response_body = (json.dumps({"success": (result>0), "new_state_size":result, "new_tokens":tokencnt}).encode()) else: response_body = (json.dumps({"success": False, "new_state_size":0, "new_tokens":0}).encode()) - elif self.path.endswith('/api/admin/clear_state'): + elif clean_path.endswith('/api/admin/clear_state'): if global_memory and savestate_limit>0 and args.admin and args.admindir and os.path.exists(args.admindir) and self.check_header_password(args.adminpassword): result = handle.clear_state_kv() response_body = (json.dumps({"success": result}).encode()) else: response_body = (json.dumps({"success": False}).encode()) - elif self.path.startswith('/api/upload/image') or self.path.startswith("/upload/image"): #comfyui compatible + elif clean_path.startswith('/api/upload/image') or clean_path.startswith("/upload/image"): #comfyui compatible lastuploadedcomfyimg = b'' formdata = self.extract_formdata_from_file_upload(body) if "file" in formdata and formdata["file"]: lastuploadedcomfyimg = formdata["file"] response_body = (json.dumps({"name": "kcpp_img2img.jpg", "subfolder": "", "type": "input"}).encode()) - elif self.path.endswith('/request'): + elif clean_path.endswith('/request'): api_format = 1 - elif self.path.endswith(('/api/v1/generate', '/api/latest/generate')): + elif clean_path.endswith(('/api/v1/generate', '/api/latest/generate')): api_format = 2 - elif self.path.endswith('/api/extra/generate/stream'): + elif clean_path.endswith('/api/extra/generate/stream'): api_format = 2 sse_stream_flag = True - elif self.path.endswith('/v1/completions') or self.path.endswith('/v1/completion') or self.path=='/completions': + elif clean_path.endswith('/v1/completions') or clean_path.endswith('/v1/completion') or clean_path=='/completions': api_format = 3 - elif self.path.endswith('/v1/chat/completions') or self.path=='/chat/completions': + elif clean_path.endswith('/v1/chat/completions') or clean_path=='/chat/completions': api_format = 4 - elif self.path.endswith('/sdapi/v1/interrogate'): + elif clean_path.endswith('/sdapi/v1/interrogate'): mmprojOverride = False if autoswapmode and mmprojName is not None: mmprojOverride = True @@ -6593,31 +6595,31 @@ Change Mode
}}).encode()) return api_format = 5 - elif self.path.endswith('/api/generate'): #ollama + elif clean_path.endswith('/api/generate'): #ollama api_format = 6 - elif self.path.endswith('/api/chat'): #ollama + elif clean_path.endswith('/api/chat'): #ollama api_format = 7 - elif self.path.endswith('/v1/responses') or self.path=='/responses': #oai-responses + elif clean_path.endswith('/v1/responses') or clean_path=='/responses': #oai-responses api_format = 8 - elif self.path.endswith('/v1/messages') or self.path=='/messages': #anthropic + elif clean_path.endswith('/v1/messages') or clean_path=='/messages': #anthropic api_format = 9 - elif self.path.endswith('/sdapi/v1/extra-single-image') or self.path.endswith('/sdapi/v1/upscale'): + elif clean_path.endswith('/sdapi/v1/extra-single-image') or clean_path.endswith('/sdapi/v1/upscale'): is_img_upscale = True - elif self.path=="/prompt" or self.path=="/images/generations" or self.path.endswith('/v1/images/generations') or self.path.endswith('/sdapi/v1/txt2img') or self.path.endswith('/sdapi/v1/img2img'): + elif clean_path=="/prompt" or clean_path=="/images/generations" or clean_path.endswith('/v1/images/generations') or clean_path.endswith('/sdapi/v1/txt2img') or clean_path.endswith('/sdapi/v1/img2img'): is_imggen = True - if self.path=="/prompt": + if clean_path=="/prompt": is_comfyui_imggen = True - elif self.path.endswith('/v1/images/generations') or self.path=="/images/generations": + elif clean_path.endswith('/v1/images/generations') or clean_path=="/images/generations": is_oai_imggen = True - elif self.path.endswith('/api/extra/transcribe') or self.path.endswith('/v1/audio/transcriptions') or self.path=="/audio/transcriptions": + elif clean_path.endswith('/api/extra/transcribe') or clean_path.endswith('/v1/audio/transcriptions') or clean_path=="/audio/transcriptions": is_transcribe = True - elif self.path.endswith('/api/extra/tts') or self.path.endswith('/v1/audio/speech') or self.path=="/audio/speech" or self.path.endswith('/tts_to_audio'): + elif clean_path.endswith('/api/extra/tts') or clean_path.endswith('/v1/audio/speech') or clean_path=="/audio/speech" or clean_path.endswith('/tts_to_audio'): is_tts = True - elif self.path.endswith('/api/extra/embeddings') or self.path.endswith('/v1/embeddings'): + elif clean_path.endswith('/api/extra/embeddings') or clean_path.endswith('/v1/embeddings'): is_embeddings = True - elif self.path.endswith('/api/extra/music/prepare'): + elif clean_path.endswith('/api/extra/music/prepare'): is_music_codes = True - elif self.path.endswith('/api/extra/music/generate'): + elif clean_path.endswith('/api/extra/music/generate'): is_music_audio = True if response_body is not None: @@ -6629,7 +6631,7 @@ Change Mode
global last_req_time last_req_time = time.time() - if not is_imggen and not is_img_upscale and not self.path.endswith('/tts_to_audio') and api_format!=5: + if not is_imggen and not is_img_upscale and not clean_path.endswith('/tts_to_audio') and api_format!=5: if not self.secure_endpoint(): return