2121import logging .handlers
2222import operator
2323import html as html_lib
24+ from urllib .parse import urlparse
2425
2526# Version scheme (MAJOR.MINOR.PATCH) should orientate on "Semantic Versioning" https://semver.org/
2627# Every change in this script should result in increasing the version number accordingly (exceptions may be cosmetic
2728# changes)
28- SERVER_VERSION = "1.3.29 "
29+ SERVER_VERSION = "1.3.30 "
2930
3031OLD_VERSION = '2.9'
3132
4243 logfile += '/'
4344logfile += 'donate-cpu-server.log'
4445handler_file = logging .handlers .RotatingFileHandler (filename = logfile , maxBytes = 100 * 1024 , backupCount = 1 )
46+ handler_file .setFormatter (logging .Formatter ('%(asctime)s %(message)s' ))
4547handler_file .setLevel (logging .ERROR )
4648logger .addHandler (handler_file )
4749
4850
49- def print_ts (msg ):
50- print ('[' + strDateTime () + '] ' + msg )
51+ def print_ts (msg ) -> None :
52+ print ('[{}] {}' . format ( strDateTime (), msg ) )
5153
5254
5355# Set up an exception hook for all uncaught exceptions so they can be logged
@@ -179,7 +181,9 @@ def latestReport(latestResults: list) -> str:
179181 return html
180182
181183
182- def crashReport (results_path : str ) -> str :
184+ def crashReport (results_path : str , query_params : dict ):
185+ pkgs = '' if query_params .get ('pkgs' ) == '1' else None
186+
183187 html = '<html><head><title>Crash report</title></head><body>\n '
184188 html += '<h1>Crash report</h1>\n '
185189 html += '<pre>\n '
@@ -191,6 +195,7 @@ def crashReport(results_path: str) -> str:
191195 continue
192196 with open (filename , 'rt' ) as file_ :
193197 datestr = None
198+ package_url = None
194199 for line in file_ :
195200 line = line .strip ()
196201 if line .startswith ('cppcheck: ' ):
@@ -202,6 +207,8 @@ def crashReport(results_path: str) -> str:
202207 continue
203208 if datestr is None and line .startswith (str (current_year ) + '-' ) or line .startswith (str (current_year - 1 ) + '-' ):
204209 datestr = line
210+ elif pkgs is not None and package_url is None and line .startswith ('ftp://' ):
211+ package_url = line
205212 elif line .startswith ('count:' ):
206213 if line .find ('Crash' ) < 0 :
207214 break
@@ -214,6 +221,8 @@ def crashReport(results_path: str) -> str:
214221 if counts [1 ] == 'Crash!' :
215222 c_head = 'Crash'
216223 html += fmt (package , datestr , c_version , c_head ) + '\n '
224+ if package_url is not None :
225+ pkgs += '{}\n ' .format (package_url )
217226 if c_head != 'Crash' :
218227 break
219228 elif line .find (' received signal ' ) != - 1 :
@@ -271,7 +280,9 @@ def crashReport(results_path: str) -> str:
271280 html += '</pre>\n '
272281
273282 html += '</body></html>\n '
274- return html
283+ if pkgs is not None :
284+ return pkgs , 'text/plain'
285+ return html , 'text/html'
275286
276287
277288def timeoutReport (results_path : str ) -> str :
@@ -609,7 +620,8 @@ def headReport(resultsPath: str) -> str:
609620 return html
610621
611622
612- def headMessageIdReport (resultPath : str , messageId : str ) -> str :
623+ def headMessageIdReport (resultPath : str , messageId : str , query_params : dict ) -> str :
624+ pkgs = '' if query_params .get ('pkgs' ) == '1' else None
613625 text = messageId + '\n '
614626 e = '[' + messageId + ']\n '
615627 for filename in sorted (glob .glob (resultPath + '/*' )):
@@ -629,8 +641,12 @@ def headMessageIdReport(resultPath: str, messageId: str) -> str:
629641 elif line .endswith (e ):
630642 if url :
631643 text += url
644+ if pkgs is not None :
645+ pkgs += url
632646 url = None
633647 text += line
648+ if pkgs is not None :
649+ return pkgs
634650 return text
635651
636652
@@ -938,83 +954,91 @@ class HttpClientThread(Thread):
938954 def __init__ (self , connection : socket .socket , cmd : str , resultPath : str , latestResults : list ) -> None :
939955 Thread .__init__ (self )
940956 self .connection = connection
941- self .cmd = cmd [:cmd .find ('\n ' )]
957+ self .cmd = cmd [:cmd .find ('\r \ n ' )]
942958 self .resultPath = resultPath
943959 self .latestResults = latestResults
944960
961+ # TODO: use a proper parser
962+ def parse_req (cmd ):
963+ req_parts = cmd .split (' ' )
964+ if len (req_parts ) != 3 or req_parts [0 ] != 'GET' or not req_parts [2 ].startswith ('HTTP' ):
965+ return None , None
966+ url_obj = urlparse (req_parts [1 ])
967+ return url_obj .path , dict (urllib .parse .parse_qsl (url_obj .query ))
968+
945969 def run (self ):
946970 try :
947971 cmd = self .cmd
948972 print_ts (cmd )
949- res = re .match (r'GET /([a-zA-Z0-9_\-\.\+%]*) HTTP' , cmd )
950- if res is None :
973+ url , queryParams = HttpClientThread .parse_req (cmd )
974+ if url is None :
975+ print_ts ('invalid request: {}' .format (cmd ))
951976 self .connection .close ()
952977 return
953- url = res .group (1 )
954- if url == '' :
978+ if url == '/' :
955979 html = overviewReport ()
956980 httpGetResponse (self .connection , html , 'text/html' )
957- elif url == 'latest.html' :
981+ elif url == '/ latest.html' :
958982 html = latestReport (self .latestResults )
959983 httpGetResponse (self .connection , html , 'text/html' )
960- elif url == 'crash.html' :
961- html = crashReport (self .resultPath )
962- httpGetResponse (self .connection , html , 'text/html' )
963- elif url == 'timeout.html' :
984+ elif url == '/ crash.html' :
985+ text , mime = crashReport (self .resultPath , queryParams )
986+ httpGetResponse (self .connection , text , mime )
987+ elif url == '/ timeout.html' :
964988 html = timeoutReport (self .resultPath )
965989 httpGetResponse (self .connection , html , 'text/html' )
966- elif url == 'stale.html' :
990+ elif url == '/ stale.html' :
967991 html = staleReport (self .resultPath )
968992 httpGetResponse (self .connection , html , 'text/html' )
969- elif url == 'diff.html' :
993+ elif url == '/ diff.html' :
970994 html = diffReport (self .resultPath )
971995 httpGetResponse (self .connection , html , 'text/html' )
972- elif url .startswith ('difftoday-' ):
973- messageId = url [10 :]
996+ elif url .startswith ('/ difftoday-' ):
997+ messageId = url [len ( '/difftoday-' ) :]
974998 text = diffMessageIdTodayReport (self .resultPath , messageId )
975999 httpGetResponse (self .connection , text , 'text/plain' )
976- elif url .startswith ('diff-' ):
977- messageId = url [5 :]
1000+ elif url .startswith ('/ diff-' ):
1001+ messageId = url [len ( '/diff-' ) :]
9781002 text = diffMessageIdReport (self .resultPath , messageId )
9791003 httpGetResponse (self .connection , text , 'text/plain' )
980- elif url == 'head.html' :
1004+ elif url == '/ head.html' :
9811005 html = headReport (self .resultPath )
9821006 httpGetResponse (self .connection , html , 'text/html' )
983- elif url .startswith ('headtoday-' ):
984- messageId = url [10 :]
1007+ elif url .startswith ('/ headtoday-' ):
1008+ messageId = url [len ( '/headtoday-' ) :]
9851009 text = headMessageIdTodayReport (self .resultPath , messageId )
9861010 httpGetResponse (self .connection , text , 'text/plain' )
987- elif url .startswith ('head-' ):
988- messageId = url [5 :]
989- text = headMessageIdReport (self .resultPath , messageId )
1011+ elif url .startswith ('/ head-' ):
1012+ messageId = url [len ( '/head-' ) :]
1013+ text = headMessageIdReport (self .resultPath , messageId , queryParams )
9901014 httpGetResponse (self .connection , text , 'text/plain' )
991- elif url == 'time_lt.html' :
1015+ elif url == '/ time_lt.html' :
9921016 text = timeReport (self .resultPath , False )
9931017 httpGetResponse (self .connection , text , 'text/html' )
994- elif url == 'time_gt.html' :
1018+ elif url == '/ time_gt.html' :
9951019 text = timeReport (self .resultPath , True )
9961020 httpGetResponse (self .connection , text , 'text/html' )
997- elif url == 'time_slow.html' :
1021+ elif url == '/ time_slow.html' :
9981022 text = timeReportSlow (self .resultPath )
9991023 httpGetResponse (self .connection , text , 'text/html' )
1000- elif url == 'check_library_function_report.html' :
1024+ elif url == '/ check_library_function_report.html' :
10011025 text = check_library_report (self .resultPath + '/' + 'info_output' , message_id = 'checkLibraryFunction' )
10021026 httpGetResponse (self .connection , text , 'text/html' )
1003- elif url == 'check_library_noreturn_report.html' :
1027+ elif url == '/ check_library_noreturn_report.html' :
10041028 text = check_library_report (self .resultPath + '/' + 'info_output' , message_id = 'checkLibraryNoReturn' )
10051029 httpGetResponse (self .connection , text , 'text/html' )
1006- elif url == 'check_library_use_ignore_report.html' :
1030+ elif url == '/ check_library_use_ignore_report.html' :
10071031 text = check_library_report (self .resultPath + '/' + 'info_output' , message_id = 'checkLibraryUseIgnore' )
10081032 httpGetResponse (self .connection , text , 'text/html' )
1009- elif url == 'check_library_check_type_report.html' :
1033+ elif url == '/ check_library_check_type_report.html' :
10101034 text = check_library_report (self .resultPath + '/' + 'info_output' , message_id = 'checkLibraryCheckType' )
10111035 httpGetResponse (self .connection , text , 'text/html' )
1012- elif url .startswith ('check_library-' ):
1013- function_name = url [len ('check_library-' ):]
1036+ elif url .startswith ('/ check_library-' ):
1037+ function_name = url [len ('/ check_library-' ):]
10141038 text = check_library_function_name (self .resultPath + '/' + 'info_output' , function_name )
10151039 httpGetResponse (self .connection , text , 'text/plain' )
10161040 else :
1017- filename = resultPath + '/' + url
1041+ filename = resultPath + url
10181042 if not os .path .isfile (filename ):
10191043 print_ts ('HTTP/1.1 404 Not Found' )
10201044 self .connection .send (b'HTTP/1.1 404 Not Found\r \n \r \n ' )
0 commit comments