Chromium Code Reviews| 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 /** |
| 22 * States displayed in each state table. | |
| 23 */ | |
| 24 static const List<CacheState> STATES = AnalysisContextStatistics_CacheRow.STAT ES; | |
| 25 | |
| 26 /** | |
| 20 * The path used to request the status of the analysis server as a whole. | 27 * The path used to request the status of the analysis server as a whole. |
| 21 */ | 28 */ |
| 22 static const String STATUS_PATH = '/status'; | 29 static const String STATUS_PATH = '/status'; |
| 23 | 30 |
| 24 /** | 31 /** |
| 32 * The path used to request the list of source files in a certain cache | |
| 33 * state. | |
| 34 */ | |
| 35 static const String CACHE_STATE_PATH = '/cache_state'; | |
| 36 | |
| 37 /** | |
| 38 * Query parameter used to represent the cache state to search for, when | |
| 39 * accessing [CACHE_STATE_PATH]. | |
| 40 */ | |
| 41 static const String STATE_QUERY_PARAM = 'state'; | |
| 42 | |
| 43 /** | |
| 44 * Query parameter used to represent the context to search for, when | |
| 45 * accessing [CACHE_STATE_PATH]. | |
| 46 */ | |
| 47 static const String CONTEXT_QUERY_PARAM = 'context'; | |
| 48 | |
| 49 /** | |
| 50 * Query parameter used to represent the descriptor to search for, when | |
| 51 * accessing [CACHE_STATE_PATH]. | |
| 52 */ | |
| 53 static const String DESCRIPTOR_QUERY_PARAM = 'descriptor'; | |
| 54 | |
| 55 /** | |
| 25 * The socket server whose status is to be reported on. | 56 * The socket server whose status is to be reported on. |
| 26 */ | 57 */ |
| 27 SocketServer _server; | 58 SocketServer _server; |
| 28 | 59 |
| 29 /** | 60 /** |
| 30 * Initialize a newly created handler for GET requests. | 61 * Initialize a newly created handler for GET requests. |
| 31 */ | 62 */ |
| 32 GetHandler(SocketServer this._server); | 63 GetHandler(SocketServer this._server); |
| 33 | 64 |
| 34 /** | 65 /** |
| 35 * Handle a GET request received by the HTTP server. | 66 * Handle a GET request received by the HTTP server. |
| 36 */ | 67 */ |
| 37 void handleGetRequest(HttpRequest request) { | 68 void handleGetRequest(HttpRequest request) { |
| 38 String path = request.uri.path; | 69 String path = request.uri.path; |
| 39 if (path == STATUS_PATH) { | 70 if (path == STATUS_PATH) { |
| 40 _returnServerStatus(request); | 71 _returnServerStatus(request); |
| 72 } else if (path == CACHE_STATE_PATH) { | |
| 73 _returnCacheState(request); | |
| 41 } else { | 74 } else { |
| 42 _returnUnknownRequest(request); | 75 _returnUnknownRequest(request); |
| 43 } | 76 } |
| 44 } | 77 } |
| 45 | 78 |
| 46 /** | 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('<p>$count files found</p>'); | |
|
Brian Wilkerson
2014/10/29 13:51:02
Need to terminate the <ul> tag.
Paul Berry
2014/10/29 18:39:11
Done.
| |
| 159 response.write('</body>'); | |
| 160 response.write('</html>'); | |
| 161 response.close(); | |
| 162 } | |
| 163 | |
| 164 /** | |
| 47 * Return a response indicating the status of the analysis server. | 165 * Return a response indicating the status of the analysis server. |
| 48 */ | 166 */ |
| 49 void _returnServerStatus(HttpRequest request) { | 167 void _returnServerStatus(HttpRequest request) { |
| 50 HttpResponse response = request.response; | 168 HttpResponse response = request.response; |
| 51 response.statusCode = HttpStatus.OK; | 169 response.statusCode = HttpStatus.OK; |
| 52 response.headers.add(HttpHeaders.CONTENT_TYPE, "text/html"); | 170 response.headers.add(HttpHeaders.CONTENT_TYPE, "text/html"); |
| 53 response.write('<html>'); | 171 response.write('<html>'); |
| 54 response.write('<head>'); | 172 response.write('<head>'); |
| 55 response.write('<title>Dart Analysis Server - Status</title>'); | 173 response.write('<title>Dart Analysis Server - Status</title>'); |
| 56 response.write('</head>'); | 174 response.write('</head>'); |
| 57 response.write('<body>'); | 175 response.write('<body>'); |
| 58 response.write('<h1>Analysis Server</h1>'); | 176 response.write('<h1>Analysis Server</h1>'); |
| 59 if (_server.analysisServer == null) { | 177 if (_server.analysisServer == null) { |
| 60 response.write('<p>Not running</p>'); | 178 response.write('<p>Not running</p>'); |
| 61 } else { | 179 } else { |
| 62 response.write('<p>Running</p>'); | 180 response.write('<p>Running</p>'); |
| 63 response.write('<h1>Analysis Contexts</h1>'); | 181 response.write('<h1>Analysis Contexts</h1>'); |
| 64 response.write('<h2>Summary</h2>'); | 182 response.write('<h2>Summary</h2>'); |
| 65 response.write('<table>'); | 183 response.write('<table>'); |
| 66 _writeRow( | 184 List headerRowText = ['Context']; |
| 67 response, | 185 headerRowText.addAll(STATES); |
| 68 ['Context', 'ERROR', 'FLUSHED', 'IN_PROCESS', 'INVALID', 'VALID'], | 186 _writeRow(response, headerRowText, true); |
| 69 true); | |
| 70 _server.analysisServer.folderMap.forEach((Folder folder, AnalysisContextIm pl context) { | 187 _server.analysisServer.folderMap.forEach((Folder folder, AnalysisContextIm pl context) { |
| 71 String key = folder.shortName; | 188 String key = folder.shortName; |
| 72 AnalysisContextStatistics statistics = context.statistics; | 189 AnalysisContextStatistics statistics = context.statistics; |
| 73 int errorCount = 0; | 190 Map<CacheState, int> totals = <CacheState, int>{}; |
| 74 int flushedCount = 0; | 191 for (CacheState state in STATES) { |
| 75 int inProcessCount = 0; | 192 totals[state] = 0; |
| 76 int invalidCount = 0; | 193 } |
| 77 int validCount = 0; | |
| 78 statistics.cacheRows.forEach((AnalysisContextStatistics_CacheRow row) { | 194 statistics.cacheRows.forEach((AnalysisContextStatistics_CacheRow row) { |
| 79 errorCount += row.errorCount; | 195 for (CacheState state in STATES) { |
| 80 flushedCount += row.flushedCount; | 196 totals[state] += row.getCount(state); |
| 81 inProcessCount += row.inProcessCount; | 197 } |
| 82 invalidCount += row.invalidCount; | |
| 83 validCount += row.validCount; | |
| 84 }); | 198 }); |
| 85 _writeRow(response, [ | 199 List rowText = ['<a href="#context_${HTML_ESCAPE.convert(key)}">$key</a> ']; |
| 86 '<a href="#context_${HTML_ESCAPE.convert(key)}">$key</a>', | 200 for (CacheState state in STATES) { |
| 87 errorCount, | 201 rowText.add(totals[state]); |
| 88 flushedCount, | 202 } |
| 89 inProcessCount, | 203 _writeRow(response, rowText); |
| 90 invalidCount, | |
| 91 validCount]); | |
| 92 }); | 204 }); |
| 93 response.write('</table>'); | 205 response.write('</table>'); |
| 94 _server.analysisServer.folderMap.forEach((Folder folder, AnalysisContextIm pl context) { | 206 _server.analysisServer.folderMap.forEach((Folder folder, AnalysisContextIm pl context) { |
| 95 String key = folder.shortName; | 207 String key = folder.shortName; |
| 96 response.write('<h2><a name="context_${HTML_ESCAPE.convert(key)}">Analys is Context: $key</a></h2>'); | 208 response.write('<h2><a name="context_${HTML_ESCAPE.convert(key)}">Analys is Context: $key</a></h2>'); |
| 97 AnalysisContextStatistics statistics = context.statistics; | 209 AnalysisContextStatistics statistics = context.statistics; |
| 98 response.write('<table>'); | 210 response.write('<table>'); |
| 99 _writeRow( | 211 _writeRow(response, headerRowText, true); |
| 100 response, | |
| 101 ['Item', 'ERROR', 'FLUSHED', 'IN_PROCESS', 'INVALID', 'VALID'], | |
| 102 true); | |
| 103 statistics.cacheRows.forEach((AnalysisContextStatistics_CacheRow row) { | 212 statistics.cacheRows.forEach((AnalysisContextStatistics_CacheRow row) { |
| 104 _writeRow( | 213 List rowText = [row.name]; |
| 105 response, | 214 for (CacheState state in STATES) { |
| 106 [row.name, | 215 String text = row.getCount(state).toString(); |
| 107 row.errorCount, | 216 Map<String, String> params = <String, String>{ |
| 108 row.flushedCount, | 217 STATE_QUERY_PARAM: state.toString(), |
| 109 row.inProcessCount, | 218 CONTEXT_QUERY_PARAM: folder.path, |
| 110 row.invalidCount, | 219 DESCRIPTOR_QUERY_PARAM: row.name |
| 111 row.validCount]); | 220 }; |
| 221 rowText.add(_makeLink(CACHE_STATE_PATH, params, text)); | |
| 222 } | |
| 223 _writeRow(response, rowText); | |
| 112 }); | 224 }); |
| 113 response.write('</table>'); | 225 response.write('</table>'); |
| 114 List<CaughtException> exceptions = statistics.exceptions; | 226 List<CaughtException> exceptions = statistics.exceptions; |
| 115 if (!exceptions.isEmpty) { | 227 if (!exceptions.isEmpty) { |
| 116 response.write('<h2>Exceptions</h2>'); | 228 response.write('<h2>Exceptions</h2>'); |
| 117 exceptions.forEach((CaughtException exception) { | 229 exceptions.forEach((CaughtException exception) { |
| 118 response.write('<p>${exception.exception}</p>'); | 230 response.write('<p>${exception.exception}</p>'); |
| 119 }); | 231 }); |
| 120 } | 232 } |
| 121 }); | 233 }); |
| 122 } | 234 } |
| 123 response.write('</body>'); | 235 response.write('</body>'); |
| 124 response.write('</html>'); | 236 response.write('</html>'); |
| 125 response.close(); | 237 response.close(); |
| 126 } | 238 } |
| 127 | 239 |
| 128 /** | 240 /** |
| 129 * Return an error in response to an unrecognized request received by the HTTP | 241 * Return an error in response to an unrecognized request received by the HTTP |
| 130 * server. | 242 * server. |
| 131 */ | 243 */ |
| 132 void _returnUnknownRequest(HttpRequest request) { | 244 void _returnUnknownRequest(HttpRequest request) { |
| 133 HttpResponse response = request.response; | 245 HttpResponse response = request.response; |
| 134 response.statusCode = HttpStatus.NOT_FOUND; | 246 response.statusCode = HttpStatus.NOT_FOUND; |
| 135 response.headers.add(HttpHeaders.CONTENT_TYPE, "text/plain"); | 247 response.headers.add(HttpHeaders.CONTENT_TYPE, "text/plain"); |
| 136 response.write('Not found'); | 248 response.write('Not found'); |
| 137 response.close(); | 249 response.close(); |
| 138 } | 250 } |
| 139 | 251 |
| 252 void _returnFailure(HttpRequest request, String message) { | |
| 253 HttpResponse response = request.response; | |
| 254 response.statusCode = HttpStatus.OK; | |
| 255 response.headers.add(HttpHeaders.CONTENT_TYPE, "text/html"); | |
| 256 response.write('<html>'); | |
| 257 response.write('<head>'); | |
| 258 response.write('<title>Dart Analysis Server - Failure</title>'); | |
| 259 response.write('</head>'); | |
| 260 response.write('<body>'); | |
| 261 response.write(HTML_ESCAPE.convert(message)); | |
| 262 response.write('</body>'); | |
| 263 response.write('</html>'); | |
| 264 response.close(); | |
| 265 } | |
| 266 | |
| 140 /** | 267 /** |
| 141 * Write a single row within a table to the given [response] object. The row | 268 * Write a single row within a table to the given [response] object. The row |
| 142 * will have one cell for each of the [columns], and will be a header row if | 269 * will have one cell for each of the [columns], and will be a header row if |
| 143 * [header] is `true`. | 270 * [header] is `true`. |
| 144 */ | 271 */ |
| 145 void _writeRow(HttpResponse response, List<Object> columns, [bool header = fal se]) { | 272 void _writeRow(HttpResponse response, List<Object> columns, [bool header = fal se]) { |
| 146 response.write('<tr>'); | 273 response.write('<tr>'); |
| 147 columns.forEach((Object value) { | 274 columns.forEach((Object value) { |
| 148 if (header) { | 275 if (header) { |
| 149 response.write('<th>'); | 276 response.write('<th>'); |
| 150 } else { | 277 } else { |
| 151 response.write('<td>'); | 278 response.write('<td>'); |
| 152 } | 279 } |
| 153 response.write(value); | 280 response.write(value); |
| 154 if (header) { | 281 if (header) { |
| 155 response.write('</th>'); | 282 response.write('</th>'); |
| 156 } else { | 283 } else { |
| 157 response.write('</td>'); | 284 response.write('</td>'); |
| 158 } | 285 } |
| 159 }); | 286 }); |
| 160 response.write('</tr>'); | 287 response.write('</tr>'); |
| 161 } | 288 } |
| 162 } | 289 } |
| OLD | NEW |