| OLD | NEW |
| 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/1.0". | 7 // Bytes for "HTTP/1.0". |
| 8 static final HTTP10 = const [72, 84, 84, 80, 47, 49, 46, 48]; | 8 static final HTTP10 = const [72, 84, 84, 80, 47, 49, 46, 48]; |
| 9 // Bytes for "HTTP/1.1". | 9 // Bytes for "HTTP/1.1". |
| 10 static final HTTP11 = const [72, 84, 84, 80, 47, 49, 46, 49]; | 10 static final HTTP11 = const [72, 84, 84, 80, 47, 49, 46, 49]; |
| 11 | 11 |
| 12 static final END_CHUNKED = const [0x30, 13, 10, 13, 10]; | 12 static final END_CHUNKED = const [0x30, 13, 10, 13, 10]; |
| 13 } | 13 } |
| 14 | 14 |
| 15 | 15 |
| 16 // Frequently used character codes. | 16 // Frequently used character codes. |
| 17 class _CharCode { | 17 class _CharCode { |
| 18 static final int HT = 9; | 18 static final int HT = 9; |
| 19 static final int LF = 10; | 19 static final int LF = 10; |
| 20 static final int CR = 13; | 20 static final int CR = 13; |
| 21 static final int SP = 32; | 21 static final int SP = 32; |
| 22 static final int COLON = 58; | 22 static final int COLON = 58; |
| 23 static final int SEMI_COLON = 59; |
| 23 } | 24 } |
| 24 | 25 |
| 25 | 26 |
| 26 // States of the HTTP parser state machine. | 27 // States of the HTTP parser state machine. |
| 27 class _State { | 28 class _State { |
| 28 static final int START = 0; | 29 static final int START = 0; |
| 29 static final int METHOD_OR_HTTP_VERSION = 1; | 30 static final int METHOD_OR_HTTP_VERSION = 1; |
| 30 static final int REQUEST_LINE_METHOD = 2; | 31 static final int REQUEST_LINE_METHOD = 2; |
| 31 static final int REQUEST_LINE_URI = 3; | 32 static final int REQUEST_LINE_URI = 3; |
| 32 static final int REQUEST_LINE_HTTP_VERSION = 4; | 33 static final int REQUEST_LINE_HTTP_VERSION = 4; |
| 33 static final int REQUEST_LINE_ENDING = 5; | 34 static final int REQUEST_LINE_ENDING = 5; |
| 34 static final int RESPONSE_LINE_STATUS_CODE = 6; | 35 static final int RESPONSE_LINE_STATUS_CODE = 6; |
| 35 static final int RESPONSE_LINE_REASON_PHRASE = 7; | 36 static final int RESPONSE_LINE_REASON_PHRASE = 7; |
| 36 static final int RESPONSE_LINE_ENDING = 8; | 37 static final int RESPONSE_LINE_ENDING = 8; |
| 37 static final int HEADER_START = 9; | 38 static final int HEADER_START = 9; |
| 38 static final int HEADER_FIELD = 10; | 39 static final int HEADER_FIELD = 10; |
| 39 static final int HEADER_VALUE_START = 11; | 40 static final int HEADER_VALUE_START = 11; |
| 40 static final int HEADER_VALUE = 12; | 41 static final int HEADER_VALUE = 12; |
| 41 static final int HEADER_VALUE_FOLDING_OR_ENDING = 13; | 42 static final int HEADER_VALUE_FOLDING_OR_ENDING = 13; |
| 42 static final int HEADER_VALUE_FOLD_OR_END = 14; | 43 static final int HEADER_VALUE_FOLD_OR_END = 14; |
| 43 static final int HEADER_ENDING = 15; | 44 static final int HEADER_ENDING = 15; |
| 44 static final int CHUNK_SIZE_STARTING_CR = 16; | 45 static final int CHUNK_SIZE_STARTING_CR = 16; |
| 45 static final int CHUNK_SIZE_STARTING_LF = 17; | 46 static final int CHUNK_SIZE_STARTING_LF = 17; |
| 46 static final int CHUNK_SIZE = 18; | 47 static final int CHUNK_SIZE = 18; |
| 47 static final int CHUNK_SIZE_ENDING = 19; | 48 static final int CHUNK_SIZE_EXTENSION = 19; |
| 48 static final int CHUNKED_BODY_DONE_CR = 20; | 49 static final int CHUNK_SIZE_ENDING = 20; |
| 49 static final int CHUNKED_BODY_DONE_LF = 21; | 50 static final int CHUNKED_BODY_DONE_CR = 21; |
| 50 static final int BODY = 22; | 51 static final int CHUNKED_BODY_DONE_LF = 22; |
| 52 static final int BODY = 23; |
| 51 } | 53 } |
| 52 | 54 |
| 53 | 55 |
| 56 // States of the HTTP parser state machine. |
| 57 class _MessageType { |
| 58 static final int UNDETERMINED = 0; |
| 59 static final int REQUEST = 1; |
| 60 static final int RESPONSE = 0; |
| 61 } |
| 62 |
| 63 |
| 54 /** | 64 /** |
| 55 * HTTP parser which parses the HTTP stream as data is supplied | 65 * HTTP parser which parses the HTTP stream as data is supplied |
| 56 * through the writeList method. As the data is parsed the events | 66 * through the writeList method. As the data is parsed the events |
| 57 * RequestStart | 67 * RequestStart |
| 68 * ResponseStart |
| 58 * UriReceived | 69 * UriReceived |
| 59 * HeaderReceived | 70 * HeaderReceived |
| 60 * HeadersComplete | 71 * HeadersComplete |
| 61 * DataReceived | 72 * DataReceived |
| 62 * DataEnd | 73 * DataEnd |
| 63 * are generated. | 74 * are generated. |
| 64 * Currently only HTTP requests with Content-Length header are supported. | 75 * Currently only HTTP requests with Content-Length header are supported. |
| 65 */ | 76 */ |
| 66 class _HttpParser { | 77 class _HttpParser { |
| 67 _HttpParser() { | 78 _HttpParser() { |
| (...skipping 67 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 135 _expect(byte, _Const.HTTP11[_httpVersionIndex]); | 146 _expect(byte, _Const.HTTP11[_httpVersionIndex]); |
| 136 _httpVersionIndex++; | 147 _httpVersionIndex++; |
| 137 } else { | 148 } else { |
| 138 _expect(byte, _CharCode.CR); | 149 _expect(byte, _CharCode.CR); |
| 139 _state = _State.REQUEST_LINE_ENDING; | 150 _state = _State.REQUEST_LINE_ENDING; |
| 140 } | 151 } |
| 141 break; | 152 break; |
| 142 | 153 |
| 143 case _State.REQUEST_LINE_ENDING: | 154 case _State.REQUEST_LINE_ENDING: |
| 144 _expect(byte, _CharCode.LF); | 155 _expect(byte, _CharCode.LF); |
| 156 _messageType = _MessageType.REQUEST; |
| 145 if (requestStart != null) { | 157 if (requestStart != null) { |
| 146 requestStart(_method_or_status_code.toString(), | 158 requestStart(_method_or_status_code.toString(), |
| 147 _uri_or_reason_phrase.toString()); | 159 _uri_or_reason_phrase.toString()); |
| 148 } | 160 } |
| 149 _method_or_status_code.clear(); | 161 _method_or_status_code.clear(); |
| 150 _uri_or_reason_phrase.clear(); | 162 _uri_or_reason_phrase.clear(); |
| 151 _state = _State.HEADER_START; | 163 _state = _State.HEADER_START; |
| 152 break; | 164 break; |
| 153 | 165 |
| 154 case _State.RESPONSE_LINE_STATUS_CODE: | 166 case _State.RESPONSE_LINE_STATUS_CODE: |
| (...skipping 12 matching lines...) Expand all Loading... |
| 167 case _State.RESPONSE_LINE_REASON_PHRASE: | 179 case _State.RESPONSE_LINE_REASON_PHRASE: |
| 168 if (byte == _CharCode.CR) { | 180 if (byte == _CharCode.CR) { |
| 169 _state = _State.RESPONSE_LINE_ENDING; | 181 _state = _State.RESPONSE_LINE_ENDING; |
| 170 } else { | 182 } else { |
| 171 _uri_or_reason_phrase.addCharCode(byte); | 183 _uri_or_reason_phrase.addCharCode(byte); |
| 172 } | 184 } |
| 173 break; | 185 break; |
| 174 | 186 |
| 175 case _State.RESPONSE_LINE_ENDING: | 187 case _State.RESPONSE_LINE_ENDING: |
| 176 _expect(byte, _CharCode.LF); | 188 _expect(byte, _CharCode.LF); |
| 177 // TODO(sgjesse): Check for valid status code. | 189 _messageType == _MessageType.RESPONSE; |
| 178 if (responseStart != null) { | 190 if (responseStart != null) { |
| 179 responseStart(Math.parseInt(_method_or_status_code.toString()), | 191 int statusCode = Math.parseInt(_method_or_status_code.toString()); |
| 180 _uri_or_reason_phrase.toString()); | 192 if (statusCode < 100 || statusCode > 599) { |
| 193 if (error != null) error("Invalid response status code"); |
| 194 _failure = true; |
| 195 } else { |
| 196 // Check whether this response will never have a body. |
| 197 _noMessageBody = |
| 198 statusCode <= 199 || statusCode == 204 || statusCode == 304; |
| 199 responseStart(statusCode, _uri_or_reason_phrase.toString()); |
| 200 } |
| 181 } | 201 } |
| 182 _method_or_status_code.clear(); | 202 _method_or_status_code.clear(); |
| 183 _uri_or_reason_phrase.clear(); | 203 _uri_or_reason_phrase.clear(); |
| 184 _state = _State.HEADER_START; | 204 _state = _State.HEADER_START; |
| 185 break; | 205 break; |
| 186 | 206 |
| 187 case _State.HEADER_START: | 207 case _State.HEADER_START: |
| 188 if (byte == _CharCode.CR) { | 208 if (byte == _CharCode.CR) { |
| 189 _state = _State.HEADER_ENDING; | 209 _state = _State.HEADER_ENDING; |
| 190 } else { | 210 } else { |
| (...skipping 63 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 254 _headerField.addCharCode(_toLowerCase(byte)); | 274 _headerField.addCharCode(_toLowerCase(byte)); |
| 255 _state = _State.HEADER_FIELD; | 275 _state = _State.HEADER_FIELD; |
| 256 } | 276 } |
| 257 } | 277 } |
| 258 break; | 278 break; |
| 259 | 279 |
| 260 case _State.HEADER_ENDING: | 280 case _State.HEADER_ENDING: |
| 261 _expect(byte, _CharCode.LF); | 281 _expect(byte, _CharCode.LF); |
| 262 if (headersComplete != null) headersComplete(); | 282 if (headersComplete != null) headersComplete(); |
| 263 | 283 |
| 264 // If there is no data get ready to process the next request. | |
| 265 if (_chunked) { | 284 if (_chunked) { |
| 266 _state = _State.CHUNK_SIZE; | 285 _state = _State.CHUNK_SIZE; |
| 267 _remainingContent = 0; | 286 _remainingContent = 0; |
| 268 } else if (_contentLength == 0) { | 287 } else if (_contentLength == 0 || |
| 288 (_messageType == _MessageType.REQUEST && |
| 289 _contentLength == -1) || |
| 290 (_messageType == _MessageType.RESPONSE && |
| 291 (_noMessageBody || _responseToMethod == "HEAD"))) { |
| 292 // If there is no message body get ready to process the |
| 293 // next request. |
| 269 if (dataEnd != null) dataEnd(); | 294 if (dataEnd != null) dataEnd(); |
| 270 _state = _State.START; | 295 _state = _State.START; |
| 271 } else if (_contentLength > 0) { | 296 } else if (_contentLength > 0) { |
| 272 _remainingContent = _contentLength; | 297 _remainingContent = _contentLength; |
| 273 _state = _State.BODY; | 298 _state = _State.BODY; |
| 274 } else { | 299 } else { |
| 275 // Neither chunked nor content length. End of body | 300 // Neither chunked nor content length. End of body |
| 276 // indicated by close. | 301 // indicated by close. |
| 277 _state = _State.BODY; | 302 _state = _State.BODY; |
| 278 } | 303 } |
| 279 break; | 304 break; |
| 280 | 305 |
| 281 case _State.CHUNK_SIZE_STARTING_CR: | 306 case _State.CHUNK_SIZE_STARTING_CR: |
| 282 _expect(byte, _CharCode.CR); | 307 _expect(byte, _CharCode.CR); |
| 283 _state = _State.CHUNK_SIZE_STARTING_LF; | 308 _state = _State.CHUNK_SIZE_STARTING_LF; |
| 284 break; | 309 break; |
| 285 | 310 |
| 286 case _State.CHUNK_SIZE_STARTING_LF: | 311 case _State.CHUNK_SIZE_STARTING_LF: |
| 287 _expect(byte, _CharCode.LF); | 312 _expect(byte, _CharCode.LF); |
| 288 _state = _State.CHUNK_SIZE; | 313 _state = _State.CHUNK_SIZE; |
| 289 break; | 314 break; |
| 290 | 315 |
| 291 case _State.CHUNK_SIZE: | 316 case _State.CHUNK_SIZE: |
| 292 if (byte == _CharCode.CR) { | 317 if (byte == _CharCode.CR) { |
| 293 _state = _State.CHUNK_SIZE_ENDING; | 318 _state = _State.CHUNK_SIZE_ENDING; |
| 319 } else if (byte == _CharCode.SEMI_COLON) { |
| 320 _state = _State.CHUNK_SIZE_EXTENSION; |
| 294 } else { | 321 } else { |
| 295 int value = _expectHexDigit(byte); | 322 int value = _expectHexDigit(byte); |
| 296 _remainingContent = _remainingContent * 16 + value; | 323 _remainingContent = _remainingContent * 16 + value; |
| 297 } | 324 } |
| 298 break; | 325 break; |
| 299 | 326 |
| 327 case _State.CHUNK_SIZE_EXTENSION: |
| 328 if (byte == _CharCode.CR) { |
| 329 _state = _State.CHUNK_SIZE_ENDING; |
| 330 } |
| 331 break; |
| 332 |
| 300 case _State.CHUNK_SIZE_ENDING: | 333 case _State.CHUNK_SIZE_ENDING: |
| 301 _expect(byte, _CharCode.LF); | 334 _expect(byte, _CharCode.LF); |
| 302 if (_remainingContent > 0) { | 335 if (_remainingContent > 0) { |
| 303 _state = _State.BODY; | 336 _state = _State.BODY; |
| 304 } else { | 337 } else { |
| 305 _state = _State.CHUNKED_BODY_DONE_CR; | 338 _state = _State.CHUNKED_BODY_DONE_CR; |
| 306 } | 339 } |
| 307 break; | 340 break; |
| 308 | 341 |
| 309 case _State.CHUNKED_BODY_DONE_CR: | 342 case _State.CHUNKED_BODY_DONE_CR: |
| (...skipping 53 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 363 int connectionClosed() { | 396 int connectionClosed() { |
| 364 if (!_chunked && _contentLength == -1) { | 397 if (!_chunked && _contentLength == -1) { |
| 365 if (dataEnd != null) dataEnd(); | 398 if (dataEnd != null) dataEnd(); |
| 366 } else { | 399 } else { |
| 367 if (error != null) { | 400 if (error != null) { |
| 368 error("Connection closed before full body was received"); | 401 error("Connection closed before full body was received"); |
| 369 } | 402 } |
| 370 } | 403 } |
| 371 } | 404 } |
| 372 | 405 |
| 406 int get messageType() => _messageType; |
| 373 int get contentLength() => _contentLength; | 407 int get contentLength() => _contentLength; |
| 374 bool get keepAlive() => _keepAlive; | 408 bool get keepAlive() => _keepAlive; |
| 375 | 409 |
| 410 void set responseToMethod(String method) => _responseToMethod = method; |
| 411 |
| 376 _reset() { | 412 _reset() { |
| 377 _state = _State.START; | 413 _state = _State.START; |
| 378 _failure = false; | 414 _failure = false; |
| 415 _messageType = _MessageType.UNDETERMINED; |
| 379 _headerField = new StringBuffer(); | 416 _headerField = new StringBuffer(); |
| 380 _headerValue = new StringBuffer(); | 417 _headerValue = new StringBuffer(); |
| 381 _method_or_status_code = new StringBuffer(); | 418 _method_or_status_code = new StringBuffer(); |
| 382 _uri_or_reason_phrase = new StringBuffer(); | 419 _uri_or_reason_phrase = new StringBuffer(); |
| 383 | 420 |
| 384 _contentLength = -1; | 421 _contentLength = -1; |
| 385 _keepAlive = false; | 422 _keepAlive = false; |
| 386 _chunked = false; | 423 _chunked = false; |
| 424 |
| 425 _noMessageBody = false; |
| 426 _responseToMethod = null; |
| 387 _remainingContent = null; | 427 _remainingContent = null; |
| 388 } | 428 } |
| 389 | 429 |
| 390 int _toLowerCase(int byte) { | 430 int _toLowerCase(int byte) { |
| 391 final int aCode = "A".charCodeAt(0); | 431 final int aCode = "A".charCodeAt(0); |
| 392 final int zCode = "Z".charCodeAt(0); | 432 final int zCode = "Z".charCodeAt(0); |
| 393 final int delta = "a".charCodeAt(0) - aCode; | 433 final int delta = "a".charCodeAt(0) - aCode; |
| 394 return (aCode <= byte && byte <= zCode) ? byte + delta : byte; | 434 return (aCode <= byte && byte <= zCode) ? byte + delta : byte; |
| 395 } | 435 } |
| 396 | 436 |
| (...skipping 13 matching lines...) Expand all Loading... |
| 410 return byte - 0x61 + 10; // a - f | 450 return byte - 0x61 + 10; // a - f |
| 411 } else { | 451 } else { |
| 412 _failure = true; | 452 _failure = true; |
| 413 return 0; | 453 return 0; |
| 414 } | 454 } |
| 415 } | 455 } |
| 416 | 456 |
| 417 int _state; | 457 int _state; |
| 418 bool _failure; | 458 bool _failure; |
| 419 int _httpVersionIndex; | 459 int _httpVersionIndex; |
| 460 int _messageType; |
| 420 StringBuffer _method_or_status_code; | 461 StringBuffer _method_or_status_code; |
| 421 StringBuffer _uri_or_reason_phrase; | 462 StringBuffer _uri_or_reason_phrase; |
| 422 StringBuffer _headerField; | 463 StringBuffer _headerField; |
| 423 StringBuffer _headerValue; | 464 StringBuffer _headerValue; |
| 424 | 465 |
| 425 int _contentLength; | 466 int _contentLength; |
| 426 bool _keepAlive; | 467 bool _keepAlive; |
| 427 bool _chunked; | 468 bool _chunked; |
| 428 | 469 |
| 470 bool _noMessageBody; |
| 471 String _responseToMethod; // Indicates the method used for the request. |
| 429 int _remainingContent; | 472 int _remainingContent; |
| 430 | 473 |
| 431 // Callbacks. | 474 // Callbacks. |
| 432 Function requestStart; | 475 Function requestStart; |
| 433 Function responseStart; | 476 Function responseStart; |
| 434 Function headerReceived; | 477 Function headerReceived; |
| 435 Function headersComplete; | 478 Function headersComplete; |
| 436 Function dataReceived; | 479 Function dataReceived; |
| 437 Function dataEnd; | 480 Function dataEnd; |
| 438 Function error; | 481 Function error; |
| 439 } | 482 } |
| OLD | NEW |