@@ -37,14 +37,20 @@ class BaseHandlerMixin:
3737
3838 def send_json_response (self , data , status = 200 ):
3939 """发送JSON响应"""
40- self .send_response (status )
41- self .send_header ('Content-Type' , 'application/json; charset=utf-8' )
42- self .send_header ('Access-Control-Allow-Origin' , '*' )
43- self .send_header ('Access-Control-Allow-Methods' , 'GET, POST, PUT, DELETE, OPTIONS' )
44- self .send_header ('Access-Control-Allow-Headers' , 'Content-Type, Authorization' )
45- self .end_headers ()
46- response = json .dumps (data , ensure_ascii = False )
47- self .wfile .write (response .encode ('utf-8' ))
40+ try :
41+ self .send_response (status )
42+ self .send_header ('Content-Type' , 'application/json; charset=utf-8' )
43+ self .send_header ('Access-Control-Allow-Origin' , '*' )
44+ self .send_header ('Access-Control-Allow-Methods' , 'GET, POST, PUT, DELETE, OPTIONS' )
45+ self .send_header ('Access-Control-Allow-Headers' , 'Content-Type, Authorization' )
46+ self .end_headers ()
47+ response = json .dumps (data , ensure_ascii = False )
48+ self .wfile .write (response .encode ('utf-8' ))
49+ except (BrokenPipeError , ConnectionResetError , ConnectionAbortedError ):
50+ # 客户端断开连接,静默处理
51+ pass
52+ except Exception as e :
53+ error_logger .debug ("Error sending JSON response: %s" , str (e ))
4854
4955 def send_error_response (self , message , status = 400 , sql_error = None ):
5056 """发送错误响应(可能包含SQL错误信息用于演示)"""
@@ -63,37 +69,43 @@ def send_error_response(self, message, status=400, sql_error=None):
6369
6470 def send_xml_response (self , data , status = 200 ):
6571 """发送XML响应"""
66- self .send_response (status )
67- self .send_header ('Content-Type' , 'application/xml; charset=utf-8' )
68- self .send_header ('Access-Control-Allow-Origin' , '*' )
69- self .send_header ('Access-Control-Allow-Methods' , 'GET, POST, PUT, DELETE, OPTIONS' )
70- self .send_header ('Access-Control-Allow-Headers' , 'Content-Type, Authorization, X-Session-Id, X-Token' )
71- self .end_headers ()
72-
73- # 将dict转换为XML
74- def dict_to_xml (d , root_name = 'response' ):
75- root = ET .Element (root_name )
76- for key , value in d .items ():
77- child = ET .SubElement (root , key )
78- if isinstance (value , dict ):
79- for k , v in value .items ():
80- sub = ET .SubElement (child , k )
81- sub .text = str (v ) if v is not None else ''
82- elif isinstance (value , list ):
83- for item in value :
84- item_el = ET .SubElement (child , 'item' )
85- if isinstance (item , dict ):
86- for k , v in item .items ():
87- sub = ET .SubElement (item_el , k )
88- sub .text = str (v ) if v is not None else ''
89- else :
90- item_el .text = str (item )
91- else :
92- child .text = str (value ) if value is not None else ''
93- return ET .tostring (root , encoding = 'unicode' )
94-
95- xml_str = '<?xml version="1.0" encoding="UTF-8"?>\n ' + dict_to_xml (data )
96- self .wfile .write (xml_str .encode ('utf-8' ))
72+ try :
73+ self .send_response (status )
74+ self .send_header ('Content-Type' , 'application/xml; charset=utf-8' )
75+ self .send_header ('Access-Control-Allow-Origin' , '*' )
76+ self .send_header ('Access-Control-Allow-Methods' , 'GET, POST, PUT, DELETE, OPTIONS' )
77+ self .send_header ('Access-Control-Allow-Headers' , 'Content-Type, Authorization, X-Session-Id, X-Token' )
78+ self .end_headers ()
79+
80+ # 将dict转换为XML
81+ def dict_to_xml (d , root_name = 'response' ):
82+ root = ET .Element (root_name )
83+ for key , value in d .items ():
84+ child = ET .SubElement (root , key )
85+ if isinstance (value , dict ):
86+ for k , v in value .items ():
87+ sub = ET .SubElement (child , k )
88+ sub .text = str (v ) if v is not None else ''
89+ elif isinstance (value , list ):
90+ for item in value :
91+ item_el = ET .SubElement (child , 'item' )
92+ if isinstance (item , dict ):
93+ for k , v in item .items ():
94+ sub = ET .SubElement (item_el , k )
95+ sub .text = str (v ) if v is not None else ''
96+ else :
97+ item_el .text = str (item )
98+ else :
99+ child .text = str (value ) if value is not None else ''
100+ return ET .tostring (root , encoding = 'unicode' )
101+
102+ xml_str = '<?xml version="1.0" encoding="UTF-8"?>\n ' + dict_to_xml (data )
103+ self .wfile .write (xml_str .encode ('utf-8' ))
104+ except (BrokenPipeError , ConnectionResetError , ConnectionAbortedError ):
105+ # 客户端断开连接,静默处理
106+ pass
107+ except Exception as e :
108+ error_logger .debug ("Error sending XML response: %s" , str (e ))
97109
98110 def send_static_file (self , filepath ):
99111 """发送静态文件"""
@@ -120,42 +132,78 @@ def send_static_file(self, filepath):
120132 self .send_header ('Content-Length' , len (content ))
121133 self .end_headers ()
122134 self .wfile .write (content )
135+ except (BrokenPipeError , ConnectionResetError , ConnectionAbortedError ):
136+ # 客户端断开连接,静默处理
137+ pass
138+ except FileNotFoundError :
139+ self .send_error (404 , 'File Not Found' )
123140 except Exception as e :
124- error_logger .exception ("Error serving static file: %s" , filepath )
125- self .send_error (500 , str (e ))
141+ error_logger .debug ("Error serving static file %s: %s" , filepath , str (e ))
142+ try :
143+ self .send_error (500 , 'Internal Server Error' )
144+ except :
145+ pass
126146
127147 def get_post_data (self ):
128148 """获取POST请求数据,支持JSON、URL-encoded和XML格式"""
129- content_length = int (self .headers .get ('Content-Length' , 0 ))
130- if content_length == 0 :
131- return {}
132-
133- post_data = self .rfile .read (content_length ).decode ('utf-8' )
134- content_type = self .headers .get ('Content-Type' , '' )
135-
136- if 'application/json' in content_type :
149+ try :
150+ content_length_str = self .headers .get ('Content-Length' , '0' )
137151 try :
138- return json .loads (post_data )
139- except :
152+ content_length = int (content_length_str )
153+ except (ValueError , TypeError ):
154+ content_length = 0
155+
156+ if content_length <= 0 :
140157 return {}
141- elif 'application/xml' in content_type or 'text/xml' in content_type :
142- # XML解析
158+
159+ # 限制最大读取长度,防止内存攻击
160+ max_length = 10 * 1024 * 1024 # 10MB
161+ if content_length > max_length :
162+ content_length = max_length
163+
164+ raw_data = self .rfile .read (content_length )
143165 try :
144- root = ET .fromstring (post_data )
166+ post_data = raw_data .decode ('utf-8' )
167+ except UnicodeDecodeError :
168+ # 尝试其他编码
169+ try :
170+ post_data = raw_data .decode ('latin-1' )
171+ except :
172+ return {}
173+
174+ content_type = self .headers .get ('Content-Type' , '' )
175+
176+ if 'application/json' in content_type :
177+ try :
178+ return json .loads (post_data )
179+ except :
180+ return {}
181+ elif 'application/xml' in content_type or 'text/xml' in content_type :
182+ # XML解析
183+ try :
184+ root = ET .fromstring (post_data )
185+ result = {}
186+ for child in root :
187+ result [child .tag ] = child .text or ''
188+ return result
189+ except :
190+ return {}
191+ else :
192+ # application/x-www-form-urlencoded
145193 result = {}
146- for child in root :
147- result [child .tag ] = child .text or ''
194+ for pair in post_data .split ('&' ):
195+ if '=' in pair :
196+ key , value = pair .split ('=' , 1 )
197+ try :
198+ result [unquote (key )] = unquote (value )
199+ except :
200+ pass
148201 return result
149- except :
150- return {}
151- else :
152- # application/x-www-form-urlencoded
153- result = {}
154- for pair in post_data .split ('&' ):
155- if '=' in pair :
156- key , value = pair .split ('=' , 1 )
157- result [unquote (key )] = unquote (value )
158- return result
202+ except (BrokenPipeError , ConnectionResetError , ConnectionAbortedError ):
203+ return {}
204+ except Exception as e :
205+ error_logger .debug ("Error reading POST data: %s" , str (e ))
206+ return {}
159207
160208 def get_content_type (self ):
161209 """获取请求的Content-Type类型"""
0 commit comments