Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(474)

Side by Side Diff: sdk/lib/io/http_parser.dart

Issue 11418010: Do not use StringBuffer to create strings from individual char (Closed) Base URL: https://dart.googlecode.com/svn/branches/bleeding_edge/dart
Patch Set: Created 8 years, 1 month ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
« no previous file with comments | « no previous file | no next file » | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 // Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file 1 // Copyright (c) 2012, 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 // Global constants. 5 // Global constants.
6 class _Const { 6 class _Const {
7 // Bytes for "HTTP". 7 // Bytes for "HTTP".
8 static const HTTP = const [72, 84, 84, 80]; 8 static const HTTP = const [72, 84, 84, 80];
9 // Bytes for "HTTP/1.". 9 // Bytes for "HTTP/1.".
10 static const HTTP1DOT = const [72, 84, 84, 80, 47, 49, 46]; 10 static const HTTP1DOT = const [72, 84, 84, 80, 47, 49, 46];
(...skipping 152 matching lines...) Expand 10 before | Expand all | Expand 10 after
163 case _State.START: 163 case _State.START:
164 if (byte == _Const.HTTP[0]) { 164 if (byte == _Const.HTTP[0]) {
165 // Start parsing method or HTTP version. 165 // Start parsing method or HTTP version.
166 _httpVersionIndex = 1; 166 _httpVersionIndex = 1;
167 _state = _State.METHOD_OR_RESPONSE_HTTP_VERSION; 167 _state = _State.METHOD_OR_RESPONSE_HTTP_VERSION;
168 } else { 168 } else {
169 // Start parsing method. 169 // Start parsing method.
170 if (!_isTokenChar(byte)) { 170 if (!_isTokenChar(byte)) {
171 throw new HttpParserException("Invalid request method"); 171 throw new HttpParserException("Invalid request method");
172 } 172 }
173 _method_or_status_code.addCharCode(byte); 173 _method_or_status_code.add(byte);
174 if (!_requestParser) { 174 if (!_requestParser) {
175 throw new HttpParserException("Invalid response line"); 175 throw new HttpParserException("Invalid response line");
176 } 176 }
177 _state = _State.REQUEST_LINE_METHOD; 177 _state = _State.REQUEST_LINE_METHOD;
178 } 178 }
179 break; 179 break;
180 180
181 case _State.METHOD_OR_RESPONSE_HTTP_VERSION: 181 case _State.METHOD_OR_RESPONSE_HTTP_VERSION:
182 if (_httpVersionIndex < _Const.HTTP.length && 182 if (_httpVersionIndex < _Const.HTTP.length &&
183 byte == _Const.HTTP[_httpVersionIndex]) { 183 byte == _Const.HTTP[_httpVersionIndex]) {
184 // Continue parsing HTTP version. 184 // Continue parsing HTTP version.
185 _httpVersionIndex++; 185 _httpVersionIndex++;
186 } else if (_httpVersionIndex == _Const.HTTP.length && 186 } else if (_httpVersionIndex == _Const.HTTP.length &&
187 byte == _CharCode.SLASH) { 187 byte == _CharCode.SLASH) {
188 // HTTP/ parsed. As method is a token this cannot be a 188 // HTTP/ parsed. As method is a token this cannot be a
189 // method anymore. 189 // method anymore.
190 _httpVersionIndex++; 190 _httpVersionIndex++;
191 if (_requestParser) { 191 if (_requestParser) {
192 throw new HttpParserException("Invalid request line"); 192 throw new HttpParserException("Invalid request line");
193 } 193 }
194 _state = _State.RESPONSE_HTTP_VERSION; 194 _state = _State.RESPONSE_HTTP_VERSION;
195 } else { 195 } else {
196 // Did not parse HTTP version. Expect method instead. 196 // Did not parse HTTP version. Expect method instead.
197 for (int i = 0; i < _httpVersionIndex; i++) { 197 for (int i = 0; i < _httpVersionIndex; i++) {
198 _method_or_status_code.addCharCode(_Const.HTTP[i]); 198 _method_or_status_code.add(_Const.HTTP[i]);
199 } 199 }
200 if (byte == _CharCode.SP) { 200 if (byte == _CharCode.SP) {
201 _state = _State.REQUEST_LINE_URI; 201 _state = _State.REQUEST_LINE_URI;
202 } else { 202 } else {
203 _method_or_status_code.addCharCode(byte); 203 _method_or_status_code.add(byte);
204 _httpVersion = _HttpVersion.UNDETERMINED; 204 _httpVersion = _HttpVersion.UNDETERMINED;
205 if (!_requestParser) { 205 if (!_requestParser) {
206 throw new HttpParserException("Invalid response line"); 206 throw new HttpParserException("Invalid response line");
207 } 207 }
208 _state = _State.REQUEST_LINE_METHOD; 208 _state = _State.REQUEST_LINE_METHOD;
209 } 209 }
210 } 210 }
211 break; 211 break;
212 212
213 case _State.RESPONSE_HTTP_VERSION: 213 case _State.RESPONSE_HTTP_VERSION:
(...skipping 22 matching lines...) Expand all
236 } 236 }
237 break; 237 break;
238 238
239 case _State.REQUEST_LINE_METHOD: 239 case _State.REQUEST_LINE_METHOD:
240 if (byte == _CharCode.SP) { 240 if (byte == _CharCode.SP) {
241 _state = _State.REQUEST_LINE_URI; 241 _state = _State.REQUEST_LINE_URI;
242 } else { 242 } else {
243 if (_Const.SEPARATORS_AND_CR_LF.indexOf(byte) != -1) { 243 if (_Const.SEPARATORS_AND_CR_LF.indexOf(byte) != -1) {
244 throw new HttpParserException("Invalid request method"); 244 throw new HttpParserException("Invalid request method");
245 } 245 }
246 _method_or_status_code.addCharCode(byte); 246 _method_or_status_code.add(byte);
247 } 247 }
248 break; 248 break;
249 249
250 case _State.REQUEST_LINE_URI: 250 case _State.REQUEST_LINE_URI:
251 if (byte == _CharCode.SP) { 251 if (byte == _CharCode.SP) {
252 if (_uri_or_reason_phrase.length == 0) { 252 if (_uri_or_reason_phrase.length == 0) {
253 throw new HttpParserException("Invalid request URI"); 253 throw new HttpParserException("Invalid request URI");
254 } 254 }
255 _state = _State.REQUEST_LINE_HTTP_VERSION; 255 _state = _State.REQUEST_LINE_HTTP_VERSION;
256 _httpVersionIndex = 0; 256 _httpVersionIndex = 0;
257 } else { 257 } else {
258 if (byte == _CharCode.CR || byte == _CharCode.LF) { 258 if (byte == _CharCode.CR || byte == _CharCode.LF) {
259 throw new HttpParserException("Invalid request URI"); 259 throw new HttpParserException("Invalid request URI");
260 } 260 }
261 _uri_or_reason_phrase.addCharCode(byte); 261 _uri_or_reason_phrase.add(byte);
262 } 262 }
263 break; 263 break;
264 264
265 case _State.REQUEST_LINE_HTTP_VERSION: 265 case _State.REQUEST_LINE_HTTP_VERSION:
266 if (_httpVersionIndex < _Const.HTTP1DOT.length) { 266 if (_httpVersionIndex < _Const.HTTP1DOT.length) {
267 _expect(byte, _Const.HTTP11[_httpVersionIndex]); 267 _expect(byte, _Const.HTTP11[_httpVersionIndex]);
268 _httpVersionIndex++; 268 _httpVersionIndex++;
269 } else if (_httpVersionIndex == _Const.HTTP1DOT.length) { 269 } else if (_httpVersionIndex == _Const.HTTP1DOT.length) {
270 if (byte == _CharCode.ONE) { 270 if (byte == _CharCode.ONE) {
271 // HTTP/1.1 parsed. 271 // HTTP/1.1 parsed.
(...skipping 10 matching lines...) Expand all
282 } 282 }
283 } else { 283 } else {
284 _expect(byte, _CharCode.CR); 284 _expect(byte, _CharCode.CR);
285 _state = _State.REQUEST_LINE_ENDING; 285 _state = _State.REQUEST_LINE_ENDING;
286 } 286 }
287 break; 287 break;
288 288
289 case _State.REQUEST_LINE_ENDING: 289 case _State.REQUEST_LINE_ENDING:
290 _expect(byte, _CharCode.LF); 290 _expect(byte, _CharCode.LF);
291 _messageType = _MessageType.REQUEST; 291 _messageType = _MessageType.REQUEST;
292 requestStart(_method_or_status_code.toString(), 292 requestStart(new String.fromCharCodes(_method_or_status_code),
293 _uri_or_reason_phrase.toString(), 293 new String.fromCharCodes(_uri_or_reason_phrase),
294 version); 294 version);
295 _method_or_status_code.clear(); 295 _method_or_status_code.clear();
296 _uri_or_reason_phrase.clear(); 296 _uri_or_reason_phrase.clear();
297 _state = _State.HEADER_START; 297 _state = _State.HEADER_START;
298 break; 298 break;
299 299
300 case _State.RESPONSE_LINE_STATUS_CODE: 300 case _State.RESPONSE_LINE_STATUS_CODE:
301 if (byte == _CharCode.SP) { 301 if (byte == _CharCode.SP) {
302 if (_method_or_status_code.length != 3) { 302 if (_method_or_status_code.length != 3) {
303 throw new HttpParserException("Invalid response status code"); 303 throw new HttpParserException("Invalid response status code");
304 } 304 }
305 _state = _State.RESPONSE_LINE_REASON_PHRASE; 305 _state = _State.RESPONSE_LINE_REASON_PHRASE;
306 } else { 306 } else {
307 if (byte < 0x30 && 0x39 < byte) { 307 if (byte < 0x30 && 0x39 < byte) {
308 throw new HttpParserException("Invalid response status code"); 308 throw new HttpParserException("Invalid response status code");
309 } else { 309 } else {
310 _method_or_status_code.addCharCode(byte); 310 _method_or_status_code.add(byte);
311 } 311 }
312 } 312 }
313 break; 313 break;
314 314
315 case _State.RESPONSE_LINE_REASON_PHRASE: 315 case _State.RESPONSE_LINE_REASON_PHRASE:
316 if (byte == _CharCode.CR) { 316 if (byte == _CharCode.CR) {
317 if (_uri_or_reason_phrase.length == 0) { 317 if (_uri_or_reason_phrase.length == 0) {
318 throw new HttpParserException("Invalid response reason phrase"); 318 throw new HttpParserException("Invalid response reason phrase");
319 } 319 }
320 _state = _State.RESPONSE_LINE_ENDING; 320 _state = _State.RESPONSE_LINE_ENDING;
321 } else { 321 } else {
322 if (byte == _CharCode.CR || byte == _CharCode.LF) { 322 if (byte == _CharCode.CR || byte == _CharCode.LF) {
323 throw new HttpParserException("Invalid response reason phrase"); 323 throw new HttpParserException("Invalid response reason phrase");
324 } 324 }
325 _uri_or_reason_phrase.addCharCode(byte); 325 _uri_or_reason_phrase.add(byte);
326 } 326 }
327 break; 327 break;
328 328
329 case _State.RESPONSE_LINE_ENDING: 329 case _State.RESPONSE_LINE_ENDING:
330 _expect(byte, _CharCode.LF); 330 _expect(byte, _CharCode.LF);
331 _messageType == _MessageType.RESPONSE; 331 _messageType == _MessageType.RESPONSE;
332 int statusCode = parseInt(_method_or_status_code.toString()); 332 int statusCode = parseInt(new String.fromCharCodes(_method_or_status _code));
333 if (statusCode < 100 || statusCode > 599) { 333 if (statusCode < 100 || statusCode > 599) {
334 throw new HttpParserException("Invalid response status code"); 334 throw new HttpParserException("Invalid response status code");
335 } else { 335 } else {
336 // Check whether this response will never have a body. 336 // Check whether this response will never have a body.
337 _noMessageBody = 337 _noMessageBody =
338 statusCode <= 199 || statusCode == 204 || statusCode == 304; 338 statusCode <= 199 || statusCode == 204 || statusCode == 304;
339 } 339 }
340 responseStart(statusCode, 340 responseStart(statusCode,
341 _uri_or_reason_phrase.toString(), 341 new String.fromCharCodes(_uri_or_reason_phrase),
342 version); 342 version);
343 _method_or_status_code.clear(); 343 _method_or_status_code.clear();
344 _uri_or_reason_phrase.clear(); 344 _uri_or_reason_phrase.clear();
345 _state = _State.HEADER_START; 345 _state = _State.HEADER_START;
346 break; 346 break;
347 347
348 case _State.HEADER_START: 348 case _State.HEADER_START:
349 if (byte == _CharCode.CR) { 349 if (byte == _CharCode.CR) {
350 _state = _State.HEADER_ENDING; 350 _state = _State.HEADER_ENDING;
351 } else { 351 } else {
352 // Start of new header field. 352 // Start of new header field.
353 _headerField.addCharCode(_toLowerCase(byte)); 353 _headerField.add(_toLowerCase(byte));
354 _state = _State.HEADER_FIELD; 354 _state = _State.HEADER_FIELD;
355 } 355 }
356 break; 356 break;
357 357
358 case _State.HEADER_FIELD: 358 case _State.HEADER_FIELD:
359 if (byte == _CharCode.COLON) { 359 if (byte == _CharCode.COLON) {
360 _state = _State.HEADER_VALUE_START; 360 _state = _State.HEADER_VALUE_START;
361 } else { 361 } else {
362 if (!_isTokenChar(byte)) { 362 if (!_isTokenChar(byte)) {
363 throw new HttpParserException("Invalid header field name"); 363 throw new HttpParserException("Invalid header field name");
364 } 364 }
365 _headerField.addCharCode(_toLowerCase(byte)); 365 _headerField.add(_toLowerCase(byte));
366 } 366 }
367 break; 367 break;
368 368
369 case _State.HEADER_VALUE_START: 369 case _State.HEADER_VALUE_START:
370 if (byte == _CharCode.CR) { 370 if (byte == _CharCode.CR) {
371 _state = _State.HEADER_VALUE_FOLDING_OR_ENDING; 371 _state = _State.HEADER_VALUE_FOLDING_OR_ENDING;
372 } else if (byte != _CharCode.SP && byte != _CharCode.HT) { 372 } else if (byte != _CharCode.SP && byte != _CharCode.HT) {
373 // Start of new header value. 373 // Start of new header value.
374 _headerValue.addCharCode(byte); 374 _headerValue.add(byte);
375 _state = _State.HEADER_VALUE; 375 _state = _State.HEADER_VALUE;
376 } 376 }
377 break; 377 break;
378 378
379 case _State.HEADER_VALUE: 379 case _State.HEADER_VALUE:
380 if (byte == _CharCode.CR) { 380 if (byte == _CharCode.CR) {
381 _state = _State.HEADER_VALUE_FOLDING_OR_ENDING; 381 _state = _State.HEADER_VALUE_FOLDING_OR_ENDING;
382 } else { 382 } else {
383 _headerValue.addCharCode(byte); 383 _headerValue.add(byte);
384 } 384 }
385 break; 385 break;
386 386
387 case _State.HEADER_VALUE_FOLDING_OR_ENDING: 387 case _State.HEADER_VALUE_FOLDING_OR_ENDING:
388 _expect(byte, _CharCode.LF); 388 _expect(byte, _CharCode.LF);
389 _state = _State.HEADER_VALUE_FOLD_OR_END; 389 _state = _State.HEADER_VALUE_FOLD_OR_END;
390 break; 390 break;
391 391
392 case _State.HEADER_VALUE_FOLD_OR_END: 392 case _State.HEADER_VALUE_FOLD_OR_END:
393 if (byte == _CharCode.SP || byte == _CharCode.HT) { 393 if (byte == _CharCode.SP || byte == _CharCode.HT) {
394 _state = _State.HEADER_VALUE_START; 394 _state = _State.HEADER_VALUE_START;
395 } else { 395 } else {
396 String headerField = _headerField.toString(); 396 String headerField = new String.fromCharCodes(_headerField);
397 String headerValue =_headerValue.toString(); 397 String headerValue = new String.fromCharCodes(_headerValue);
398 bool reportHeader = true; 398 bool reportHeader = true;
399 if (headerField == "content-length" && !_chunked) { 399 if (headerField == "content-length" && !_chunked) {
400 // Ignore the Content-Length header if Transfer-Encoding 400 // Ignore the Content-Length header if Transfer-Encoding
401 // is chunked (RFC 2616 section 4.4) 401 // is chunked (RFC 2616 section 4.4)
402 _contentLength = parseInt(headerValue); 402 _contentLength = parseInt(headerValue);
403 } else if (headerField == "connection") { 403 } else if (headerField == "connection") {
404 List<String> tokens = _tokenizeFieldValue(headerValue); 404 List<String> tokens = _tokenizeFieldValue(headerValue);
405 for (int i = 0; i < tokens.length; i++) { 405 for (int i = 0; i < tokens.length; i++) {
406 String token = tokens[i].toLowerCase(); 406 String token = tokens[i].toLowerCase();
407 if (token == "keep-alive") { 407 if (token == "keep-alive") {
(...skipping 16 matching lines...) Expand all
424 if (reportHeader) { 424 if (reportHeader) {
425 headerReceived(headerField, headerValue); 425 headerReceived(headerField, headerValue);
426 } 426 }
427 _headerField.clear(); 427 _headerField.clear();
428 _headerValue.clear(); 428 _headerValue.clear();
429 429
430 if (byte == _CharCode.CR) { 430 if (byte == _CharCode.CR) {
431 _state = _State.HEADER_ENDING; 431 _state = _State.HEADER_ENDING;
432 } else { 432 } else {
433 // Start of new header field. 433 // Start of new header field.
434 _headerField.addCharCode(_toLowerCase(byte)); 434 _headerField.add(_toLowerCase(byte));
435 _state = _State.HEADER_FIELD; 435 _state = _State.HEADER_FIELD;
436 } 436 }
437 } 437 }
438 break; 438 break;
439 439
440 case _State.HEADER_ENDING: 440 case _State.HEADER_ENDING:
441 _expect(byte, _CharCode.LF); 441 _expect(byte, _CharCode.LF);
442 // If a request message has neither Content-Length nor 442 // If a request message has neither Content-Length nor
443 // Transfer-Encoding the message must not have a body (RFC 443 // Transfer-Encoding the message must not have a body (RFC
444 // 2616 section 4.3). 444 // 2616 section 4.3).
(...skipping 206 matching lines...) Expand 10 before | Expand all | Expand 10 after
651 return result; 651 return result;
652 } 652 }
653 653
654 void _bodyEnd() { 654 void _bodyEnd() {
655 dataEnd(_messageType == _MessageType.RESPONSE && !_persistentConnection); 655 dataEnd(_messageType == _MessageType.RESPONSE && !_persistentConnection);
656 } 656 }
657 657
658 _reset() { 658 _reset() {
659 _state = _State.START; 659 _state = _State.START;
660 _messageType = _MessageType.UNDETERMINED; 660 _messageType = _MessageType.UNDETERMINED;
661 _headerField = new StringBuffer(); 661 _headerField = new List();
662 _headerValue = new StringBuffer(); 662 _headerValue = new List();
663 _method_or_status_code = new StringBuffer(); 663 _method_or_status_code = new List();
664 _uri_or_reason_phrase = new StringBuffer(); 664 _uri_or_reason_phrase = new List();
665 665
666 _httpVersion = _HttpVersion.UNDETERMINED; 666 _httpVersion = _HttpVersion.UNDETERMINED;
667 _contentLength = -1; 667 _contentLength = -1;
668 _persistentConnection = false; 668 _persistentConnection = false;
669 _connectionUpgrade = false; 669 _connectionUpgrade = false;
670 _chunked = false; 670 _chunked = false;
671 671
672 _noMessageBody = false; 672 _noMessageBody = false;
673 _responseToMethod = null; 673 _responseToMethod = null;
674 _remainingContent = null; 674 _remainingContent = null;
(...skipping 53 matching lines...) Expand 10 before | Expand all | Expand 10 after
728 728
729 // The data that is currently being parsed. 729 // The data that is currently being parsed.
730 List<int> _buffer; 730 List<int> _buffer;
731 int _index; 731 int _index;
732 int _lastIndex; 732 int _lastIndex;
733 733
734 bool _requestParser; 734 bool _requestParser;
735 int _state; 735 int _state;
736 int _httpVersionIndex; 736 int _httpVersionIndex;
737 int _messageType; 737 int _messageType;
738 StringBuffer _method_or_status_code; 738 List _method_or_status_code;
739 StringBuffer _uri_or_reason_phrase; 739 List _uri_or_reason_phrase;
740 StringBuffer _headerField; 740 List _headerField;
741 StringBuffer _headerValue; 741 List _headerValue;
742 742
743 int _httpVersion; 743 int _httpVersion;
744 int _contentLength; 744 int _contentLength;
745 bool _persistentConnection; 745 bool _persistentConnection;
746 bool _connectionUpgrade; 746 bool _connectionUpgrade;
747 bool _chunked; 747 bool _chunked;
748 748
749 bool _noMessageBody; 749 bool _noMessageBody;
750 String _responseToMethod; // Indicates the method used for the request. 750 String _responseToMethod; // Indicates the method used for the request.
751 int _remainingContent; 751 int _remainingContent;
752 752
753 // Callbacks. 753 // Callbacks.
754 Function requestStart; 754 Function requestStart;
755 Function responseStart; 755 Function responseStart;
756 Function headerReceived; 756 Function headerReceived;
757 Function headersComplete; 757 Function headersComplete;
758 Function dataReceived; 758 Function dataReceived;
759 Function dataEnd; 759 Function dataEnd;
760 Function error; 760 Function error;
761 Function closed; 761 Function closed;
762 } 762 }
763 763
764 764
765 class HttpParserException implements Exception { 765 class HttpParserException implements Exception {
766 const HttpParserException([String this.message = ""]); 766 const HttpParserException([String this.message = ""]);
767 String toString() => "HttpParserException: $message"; 767 String toString() => "HttpParserException: $message";
768 final String message; 768 final String message;
769 } 769 }
OLDNEW
« no previous file with comments | « no previous file | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698