| OLD | NEW |
| 1 // Copyright (c) 2014, the Dart project authors. Please see the AUTHORS file | 1 // Copyright (c) 2014, the Dart project authors. Please see the AUTHORS file |
| 2 // for details. All rights reserved. Use of this source code is governed by a | 2 // for details. All rights reserved. Use of this source code is governed by a |
| 3 // BSD-style license that can be found in the LICENSE file. | 3 // BSD-style license that can be found in the LICENSE file. |
| 4 | 4 |
| 5 library get.handler; | 5 library get.handler; |
| 6 | 6 |
| 7 import 'dart:convert'; | 7 import 'dart:convert'; |
| 8 import 'dart:io'; | 8 import 'dart:io'; |
| 9 | 9 |
| 10 import 'package:analysis_server/src/socket_server.dart'; | 10 import 'package:analysis_server/src/socket_server.dart'; |
| 11 import 'package:analyzer/file_system/file_system.dart'; | 11 import 'package:analyzer/file_system/file_system.dart'; |
| 12 import 'package:analyzer/src/generated/source.dart'; |
| 12 import 'package:analyzer/src/generated/engine.dart'; | 13 import 'package:analyzer/src/generated/engine.dart'; |
| 13 import 'package:analyzer/src/generated/java_engine.dart'; | 14 import 'package:analyzer/src/generated/java_engine.dart'; |
| 15 import 'analysis_server.dart'; |
| 14 | 16 |
| 15 /** | 17 /** |
| 16 * Instances of the class [GetHandler] handle GET requests. | 18 * Instances of the class [GetHandler] handle GET requests. |
| 17 */ | 19 */ |
| 18 class GetHandler { | 20 class GetHandler { |
| 19 /** | 21 /** |
| 20 * The path used to request the status of the analysis server as a whole. | 22 * The path used to request the status of the analysis server as a whole. |
| 21 */ | 23 */ |
| 22 static const String STATUS_PATH = '/status'; | 24 static const String STATUS_PATH = '/status'; |
| 23 | 25 |
| 24 /** | 26 /** |
| 27 * The path used to request the list of source files in a certain cache |
| 28 * state. |
| 29 */ |
| 30 static const String CACHE_STATE_PATH = '/cache_state'; |
| 31 |
| 32 /** |
| 33 * Query parameter used to represent the cache state to search for, when |
| 34 * accessing [CACHE_STATE_PATH]. |
| 35 */ |
| 36 static const String STATE_QUERY_PARAM = 'state'; |
| 37 |
| 38 /** |
| 39 * Query parameter used to represent the context to search for, when |
| 40 * accessing [CACHE_STATE_PATH]. |
| 41 */ |
| 42 static const String CONTEXT_QUERY_PARAM = 'context'; |
| 43 |
| 44 /** |
| 45 * Query parameter used to represent the descriptor to search for, when |
| 46 * accessing [CACHE_STATE_PATH]. |
| 47 */ |
| 48 static const String DESCRIPTOR_QUERY_PARAM = 'descriptor'; |
| 49 |
| 50 /** |
| 25 * The socket server whose status is to be reported on. | 51 * The socket server whose status is to be reported on. |
| 26 */ | 52 */ |
| 27 SocketServer _server; | 53 SocketServer _server; |
| 28 | 54 |
| 29 /** | 55 /** |
| 30 * Buffer containing strings printed by the analysis server. | 56 * Buffer containing strings printed by the analysis server. |
| 31 */ | 57 */ |
| 32 List<String> _printBuffer; | 58 List<String> _printBuffer; |
| 33 | 59 |
| 34 /** | 60 /** |
| 35 * Initialize a newly created handler for GET requests. | 61 * Initialize a newly created handler for GET requests. |
| 36 */ | 62 */ |
| 37 GetHandler(this._server, this._printBuffer); | 63 GetHandler(this._server, this._printBuffer); |
| 38 | 64 |
| 39 /** | 65 /** |
| 40 * Handle a GET request received by the HTTP server. | 66 * Handle a GET request received by the HTTP server. |
| 41 */ | 67 */ |
| 42 void handleGetRequest(HttpRequest request) { | 68 void handleGetRequest(HttpRequest request) { |
| 43 String path = request.uri.path; | 69 String path = request.uri.path; |
| 44 if (path == STATUS_PATH) { | 70 if (path == STATUS_PATH) { |
| 45 _returnServerStatus(request); | 71 _returnServerStatus(request); |
| 72 } else if (path == CACHE_STATE_PATH) { |
| 73 _returnCacheState(request); |
| 46 } else { | 74 } else { |
| 47 _returnUnknownRequest(request); | 75 _returnUnknownRequest(request); |
| 48 } | 76 } |
| 49 } | 77 } |
| 50 | 78 |
| 51 /** | 79 /** |
| 80 * Create a link to [path] with query parameters [params], with inner HTML |
| 81 * [innerHtml]. |
| 82 */ |
| 83 String _makeLink(String path, Map<String, String> params, String innerHtml) { |
| 84 Uri uri = new Uri(path: path, queryParameters: params); |
| 85 return '<a href="${HTML_ESCAPE.convert(uri.toString())}">$innerHtml</a>'; |
| 86 } |
| 87 |
| 88 /** |
| 89 * Return a response indicating the set of source files in a certain cache |
| 90 * state. |
| 91 */ |
| 92 void _returnCacheState(HttpRequest request) { |
| 93 // Figure out what CacheState is being searched for. |
| 94 String stateQueryParam = request.uri.queryParameters[STATE_QUERY_PARAM]; |
| 95 if (stateQueryParam == null) { |
| 96 return _returnFailure(request, |
| 97 'Query parameter $STATE_QUERY_PARAM required'); |
| 98 } |
| 99 CacheState stateFilter = null; |
| 100 for (CacheState value in CacheState.values) { |
| 101 if (value.toString() == stateQueryParam) { |
| 102 stateFilter = value; |
| 103 } |
| 104 } |
| 105 if (stateFilter == null) { |
| 106 return _returnFailure(request, |
| 107 'Query parameter $STATE_QUERY_PARAM is invalid'); |
| 108 } |
| 109 |
| 110 // Figure out which context is being searched for. |
| 111 String contextFilter = request.uri.queryParameters[CONTEXT_QUERY_PARAM]; |
| 112 if (contextFilter == null) { |
| 113 return _returnFailure(request, |
| 114 'Query parameter $CONTEXT_QUERY_PARAM required'); |
| 115 } |
| 116 |
| 117 // Figure out which descriptor is being searched for. |
| 118 String descriptorFilter = |
| 119 request.uri.queryParameters[DESCRIPTOR_QUERY_PARAM]; |
| 120 if (descriptorFilter == null) { |
| 121 return _returnFailure(request, |
| 122 'Query parameter $DESCRIPTOR_QUERY_PARAM required'); |
| 123 } |
| 124 |
| 125 AnalysisServer analysisServer = _server.analysisServer; |
| 126 if (analysisServer == null) { |
| 127 return _returnFailure(request, 'Analysis server not running'); |
| 128 } |
| 129 HttpResponse response = request.response; |
| 130 response.statusCode = HttpStatus.OK; |
| 131 response.headers.add(HttpHeaders.CONTENT_TYPE, "text/html"); |
| 132 response.write('<html>'); |
| 133 response.write('<head>'); |
| 134 response.write('<title>Dart Analysis Server - Search result</title>'); |
| 135 response.write('</head>'); |
| 136 response.write('<body>'); |
| 137 response.write('<h1>'); |
| 138 response.write('Files with state ${HTML_ESCAPE.convert(stateQueryParam)}'); |
| 139 response.write(' for descriptor ${HTML_ESCAPE.convert(descriptorFilter)}'); |
| 140 response.write(' in context ${HTML_ESCAPE.convert(contextFilter)}'); |
| 141 response.write('</h1>'); |
| 142 response.write('<ul>'); |
| 143 int count = 0; |
| 144 analysisServer.folderMap.forEach((Folder folder, |
| 145 AnalysisContextImpl context) { |
| 146 if (folder.path != contextFilter) { |
| 147 return; |
| 148 } |
| 149 context.visitCacheItems((Source source, SourceEntry dartEntry, |
| 150 DataDescriptor rowDesc, CacheState state) { |
| 151 if (state != stateFilter || rowDesc.toString() != descriptorFilter) { |
| 152 return; |
| 153 } |
| 154 response.write('<li>${HTML_ESCAPE.convert(source.fullName)}</li>'); |
| 155 count++; |
| 156 }); |
| 157 }); |
| 158 response.write('</ul>'); |
| 159 response.write('<p>$count files found</p>'); |
| 160 response.write('</body>'); |
| 161 response.write('</html>'); |
| 162 response.close(); |
| 163 } |
| 164 |
| 165 /** |
| 52 * Return a response indicating the status of the analysis server. | 166 * Return a response indicating the status of the analysis server. |
| 53 */ | 167 */ |
| 54 void _returnServerStatus(HttpRequest request) { | 168 void _returnServerStatus(HttpRequest request) { |
| 55 HttpResponse response = request.response; | 169 HttpResponse response = request.response; |
| 56 response.statusCode = HttpStatus.OK; | 170 response.statusCode = HttpStatus.OK; |
| 57 response.headers.add(HttpHeaders.CONTENT_TYPE, "text/html"); | 171 response.headers.add(HttpHeaders.CONTENT_TYPE, "text/html"); |
| 58 response.write('<html>'); | 172 response.write('<html>'); |
| 59 response.write('<head>'); | 173 response.write('<head>'); |
| 60 response.write('<title>Dart Analysis Server - Status</title>'); | 174 response.write('<title>Dart Analysis Server - Status</title>'); |
| 61 response.write('</head>'); | 175 response.write('</head>'); |
| 62 response.write('<body>'); | 176 response.write('<body>'); |
| 63 response.write('<h1>Analysis Server</h1>'); | 177 response.write('<h1>Analysis Server</h1>'); |
| 64 if (_server.analysisServer == null) { | 178 if (_server.analysisServer == null) { |
| 65 response.write('<p>Not running</p>'); | 179 response.write('<p>Not running</p>'); |
| 66 } else { | 180 } else { |
| 67 response.write('<p>Running</p>'); | 181 response.write('<p>Running</p>'); |
| 68 response.write('<h1>Analysis Contexts</h1>'); | 182 response.write('<h1>Analysis Contexts</h1>'); |
| 69 response.write('<h2>Summary</h2>'); | 183 response.write('<h2>Summary</h2>'); |
| 70 response.write('<table>'); | 184 response.write('<table>'); |
| 71 _writeRow( | 185 List headerRowText = ['Context']; |
| 72 response, | 186 headerRowText.addAll(CacheState.values); |
| 73 ['Context', 'ERROR', 'FLUSHED', 'IN_PROCESS', 'INVALID', 'VALID'], | 187 _writeRow(response, headerRowText, true); |
| 74 true); | |
| 75 _server.analysisServer.folderMap.forEach((Folder folder, AnalysisContextIm
pl context) { | 188 _server.analysisServer.folderMap.forEach((Folder folder, AnalysisContextIm
pl context) { |
| 76 String key = folder.shortName; | 189 String key = folder.shortName; |
| 77 AnalysisContextStatistics statistics = context.statistics; | 190 AnalysisContextStatistics statistics = context.statistics; |
| 78 int errorCount = 0; | 191 Map<CacheState, int> totals = <CacheState, int>{}; |
| 79 int flushedCount = 0; | 192 for (CacheState state in CacheState.values) { |
| 80 int inProcessCount = 0; | 193 totals[state] = 0; |
| 81 int invalidCount = 0; | 194 } |
| 82 int validCount = 0; | |
| 83 statistics.cacheRows.forEach((AnalysisContextStatistics_CacheRow row) { | 195 statistics.cacheRows.forEach((AnalysisContextStatistics_CacheRow row) { |
| 84 errorCount += row.errorCount; | 196 for (CacheState state in CacheState.values) { |
| 85 flushedCount += row.flushedCount; | 197 totals[state] += row.getCount(state); |
| 86 inProcessCount += row.inProcessCount; | 198 } |
| 87 invalidCount += row.invalidCount; | |
| 88 validCount += row.validCount; | |
| 89 }); | 199 }); |
| 90 _writeRow(response, [ | 200 List rowText = ['<a href="#context_${HTML_ESCAPE.convert(key)}">$key</a>
']; |
| 91 '<a href="#context_${HTML_ESCAPE.convert(key)}">$key</a>', | 201 for (CacheState state in CacheState.values) { |
| 92 errorCount, | 202 rowText.add(totals[state]); |
| 93 flushedCount, | 203 } |
| 94 inProcessCount, | 204 _writeRow(response, rowText); |
| 95 invalidCount, | |
| 96 validCount]); | |
| 97 }); | 205 }); |
| 98 response.write('</table>'); | 206 response.write('</table>'); |
| 99 _server.analysisServer.folderMap.forEach((Folder folder, AnalysisContextIm
pl context) { | 207 _server.analysisServer.folderMap.forEach((Folder folder, AnalysisContextIm
pl context) { |
| 100 String key = folder.shortName; | 208 String key = folder.shortName; |
| 101 response.write('<h2><a name="context_${HTML_ESCAPE.convert(key)}">Analys
is Context: $key</a></h2>'); | 209 response.write('<h2><a name="context_${HTML_ESCAPE.convert(key)}">Analys
is Context: $key</a></h2>'); |
| 102 AnalysisContextStatistics statistics = context.statistics; | 210 AnalysisContextStatistics statistics = context.statistics; |
| 103 response.write('<table>'); | 211 response.write('<table>'); |
| 104 _writeRow( | 212 _writeRow(response, headerRowText, true); |
| 105 response, | |
| 106 ['Item', 'ERROR', 'FLUSHED', 'IN_PROCESS', 'INVALID', 'VALID'], | |
| 107 true); | |
| 108 statistics.cacheRows.forEach((AnalysisContextStatistics_CacheRow row) { | 213 statistics.cacheRows.forEach((AnalysisContextStatistics_CacheRow row) { |
| 109 _writeRow( | 214 List rowText = [row.name]; |
| 110 response, | 215 for (CacheState state in CacheState.values) { |
| 111 [row.name, | 216 String text = row.getCount(state).toString(); |
| 112 row.errorCount, | 217 Map<String, String> params = <String, String>{ |
| 113 row.flushedCount, | 218 STATE_QUERY_PARAM: state.toString(), |
| 114 row.inProcessCount, | 219 CONTEXT_QUERY_PARAM: folder.path, |
| 115 row.invalidCount, | 220 DESCRIPTOR_QUERY_PARAM: row.name |
| 116 row.validCount]); | 221 }; |
| 222 rowText.add(_makeLink(CACHE_STATE_PATH, params, text)); |
| 223 } |
| 224 _writeRow(response, rowText); |
| 117 }); | 225 }); |
| 118 response.write('</table>'); | 226 response.write('</table>'); |
| 119 List<CaughtException> exceptions = statistics.exceptions; | 227 List<CaughtException> exceptions = statistics.exceptions; |
| 120 if (!exceptions.isEmpty) { | 228 if (!exceptions.isEmpty) { |
| 121 response.write('<h2>Exceptions</h2>'); | 229 response.write('<h2>Exceptions</h2>'); |
| 122 exceptions.forEach((CaughtException exception) { | 230 exceptions.forEach((CaughtException exception) { |
| 123 response.write('<p>${exception.exception}</p>'); | 231 response.write('<p>${exception.exception}</p>'); |
| 124 }); | 232 }); |
| 125 } | 233 } |
| 126 }); | 234 }); |
| (...skipping 12 matching lines...) Expand all Loading... |
| 139 * server. | 247 * server. |
| 140 */ | 248 */ |
| 141 void _returnUnknownRequest(HttpRequest request) { | 249 void _returnUnknownRequest(HttpRequest request) { |
| 142 HttpResponse response = request.response; | 250 HttpResponse response = request.response; |
| 143 response.statusCode = HttpStatus.NOT_FOUND; | 251 response.statusCode = HttpStatus.NOT_FOUND; |
| 144 response.headers.add(HttpHeaders.CONTENT_TYPE, "text/plain"); | 252 response.headers.add(HttpHeaders.CONTENT_TYPE, "text/plain"); |
| 145 response.write('Not found'); | 253 response.write('Not found'); |
| 146 response.close(); | 254 response.close(); |
| 147 } | 255 } |
| 148 | 256 |
| 257 void _returnFailure(HttpRequest request, String message) { |
| 258 HttpResponse response = request.response; |
| 259 response.statusCode = HttpStatus.OK; |
| 260 response.headers.add(HttpHeaders.CONTENT_TYPE, "text/html"); |
| 261 response.write('<html>'); |
| 262 response.write('<head>'); |
| 263 response.write('<title>Dart Analysis Server - Failure</title>'); |
| 264 response.write('</head>'); |
| 265 response.write('<body>'); |
| 266 response.write(HTML_ESCAPE.convert(message)); |
| 267 response.write('</body>'); |
| 268 response.write('</html>'); |
| 269 response.close(); |
| 270 } |
| 271 |
| 149 /** | 272 /** |
| 150 * Write a single row within a table to the given [response] object. The row | 273 * Write a single row within a table to the given [response] object. The row |
| 151 * will have one cell for each of the [columns], and will be a header row if | 274 * will have one cell for each of the [columns], and will be a header row if |
| 152 * [header] is `true`. | 275 * [header] is `true`. |
| 153 */ | 276 */ |
| 154 void _writeRow(HttpResponse response, List<Object> columns, [bool header = fal
se]) { | 277 void _writeRow(HttpResponse response, List<Object> columns, [bool header = fal
se]) { |
| 155 response.write('<tr>'); | 278 response.write('<tr>'); |
| 156 columns.forEach((Object value) { | 279 columns.forEach((Object value) { |
| 157 if (header) { | 280 if (header) { |
| 158 response.write('<th>'); | 281 response.write('<th>'); |
| 159 } else { | 282 } else { |
| 160 response.write('<td>'); | 283 response.write('<td>'); |
| 161 } | 284 } |
| 162 response.write(value); | 285 response.write(value); |
| 163 if (header) { | 286 if (header) { |
| 164 response.write('</th>'); | 287 response.write('</th>'); |
| 165 } else { | 288 } else { |
| 166 response.write('</td>'); | 289 response.write('</td>'); |
| 167 } | 290 } |
| 168 }); | 291 }); |
| 169 response.write('</tr>'); | 292 response.write('</tr>'); |
| 170 } | 293 } |
| 171 } | 294 } |
| OLD | NEW |