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

Side by Side Diff: runtime/bin/http_impl.dart

Issue 9958059: Discard HTTP data written after a socket error (Closed) Base URL: https://dart.googlecode.com/svn/branches/bleeding_edge/dart
Patch Set: Created 8 years, 8 months 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 class _HttpRequestResponseBase { 5 class _HttpRequestResponseBase {
6 _HttpRequestResponseBase(_HttpConnectionBase this._httpConnection) 6 _HttpRequestResponseBase(_HttpConnectionBase this._httpConnection)
7 : _contentLength = -1, 7 : _contentLength = -1,
8 _keepAlive = false, 8 _keepAlive = false,
9 _headers = new Map(); 9 _headers = new Map();
10 10
11 int get contentLength() => _contentLength; 11 int get contentLength() => _contentLength;
12 bool get keepAlive() => _keepAlive; 12 bool get keepAlive() => _keepAlive;
13 Map get headers() => _headers; 13 Map get headers() => _headers;
14 14
15 void _setHeader(String name, String value) { 15 void _setHeader(String name, String value) {
16 _headers[name.toLowerCase()] = value; 16 _headers[name.toLowerCase()] = value;
17 } 17 }
18 18
19 bool _write(List<int> data, bool copyBuffer) { 19 bool _write(List<int> data, bool copyBuffer) {
20 bool allWritten = true; 20 bool allWritten = true;
21 if (data.length > 0) { 21 if (data.length > 0) {
22 if (_contentLength < 0) { 22 if (_contentLength < 0) {
23 // Write chunk size if transfer encoding is chunked. 23 // Write chunk size if transfer encoding is chunked.
24 _writeHexString(data.length); 24 _writeHexString(data.length);
25 _writeCRLF(); 25 _writeCRLF();
26 _httpConnection.outputStream.write(data, copyBuffer); 26 _httpConnection._write(data, copyBuffer);
27 allWritten = _writeCRLF(); 27 allWritten = _writeCRLF();
28 } else { 28 } else {
29 allWritten = _httpConnection.outputStream.write(data, copyBuffer); 29 allWritten = _httpConnection._write(data, copyBuffer);
30 } 30 }
31 } 31 }
32 return allWritten; 32 return allWritten;
33 } 33 }
34 34
35 bool _writeList(List<int> data, int offset, int count) { 35 bool _writeList(List<int> data, int offset, int count) {
36 bool allWritten = true; 36 bool allWritten = true;
37 if (count > 0) { 37 if (count > 0) {
38 if (_contentLength < 0) { 38 if (_contentLength < 0) {
39 // Write chunk size if transfer encoding is chunked. 39 // Write chunk size if transfer encoding is chunked.
40 _writeHexString(count); 40 _writeHexString(count);
41 _writeCRLF(); 41 _writeCRLF();
42 _httpConnection.outputStream.writeFrom(data, offset, count); 42 _httpConnection._writeFrom(data, offset, count);
43 allWritten = _writeCRLF(); 43 allWritten = _writeCRLF();
44 } else { 44 } else {
45 allWritten = _httpConnection.outputStream.writeFrom(data, offset, count) ; 45 allWritten = _httpConnection._writeFrom(data, offset, count);
46 } 46 }
47 } 47 }
48 return allWritten; 48 return allWritten;
49 } 49 }
50 50
51 bool _writeDone() { 51 bool _writeDone() {
52 bool allWritten = true; 52 bool allWritten = true;
53 if (_contentLength < 0) { 53 if (_contentLength < 0) {
54 // Terminate the content if transfer encoding is chunked. 54 // Terminate the content if transfer encoding is chunked.
55 allWritten = _httpConnection.outputStream.write(_Const.END_CHUNKED); 55 allWritten = _httpConnection._write(_Const.END_CHUNKED);
56 } 56 }
57 return allWritten; 57 return allWritten;
58 } 58 }
59 59
60 bool _writeHeaders() { 60 bool _writeHeaders() {
61 List<int> data; 61 List<int> data;
62 62
63 // Format headers. 63 // Format headers.
64 _headers.forEach((String name, String value) { 64 _headers.forEach((String name, String value) {
65 data = name.charCodes(); 65 data = name.charCodes();
66 _httpConnection.outputStream.write(data); 66 _httpConnection._write(data);
67 data = ": ".charCodes(); 67 data = ": ".charCodes();
68 _httpConnection.outputStream.write(data); 68 _httpConnection._write(data);
69 data = value.charCodes(); 69 data = value.charCodes();
70 _httpConnection.outputStream.write(data); 70 _httpConnection._write(data);
71 _writeCRLF(); 71 _writeCRLF();
72 }); 72 });
73 // Terminate header. 73 // Terminate header.
74 return _writeCRLF(); 74 return _writeCRLF();
75 } 75 }
76 76
77 bool _writeHexString(int x) { 77 bool _writeHexString(int x) {
78 final List<int> hexDigits = [0x30, 0x31, 0x32, 0x33, 0x34, 78 final List<int> hexDigits = [0x30, 0x31, 0x32, 0x33, 0x34,
79 0x35, 0x36, 0x37, 0x38, 0x39, 79 0x35, 0x36, 0x37, 0x38, 0x39,
80 0x41, 0x42, 0x43, 0x44, 0x45, 0x46]; 80 0x41, 0x42, 0x43, 0x44, 0x45, 0x46];
81 ByteArray hex = new ByteArray(10); 81 ByteArray hex = new ByteArray(10);
82 int index = hex.length; 82 int index = hex.length;
83 while (x > 0) { 83 while (x > 0) {
84 index--; 84 index--;
85 hex[index] = hexDigits[x % 16]; 85 hex[index] = hexDigits[x % 16];
86 x = x >> 4; 86 x = x >> 4;
87 } 87 }
88 return _httpConnection.outputStream.writeFrom(hex, index, hex.length - index ); 88 return _httpConnection._writeFrom(hex, index, hex.length - index);
89 } 89 }
90 90
91 bool _writeCRLF() { 91 bool _writeCRLF() {
92 final CRLF = const [_CharCode.CR, _CharCode.LF]; 92 final CRLF = const [_CharCode.CR, _CharCode.LF];
93 return _httpConnection.outputStream.write(CRLF); 93 return _httpConnection._write(CRLF);
94 } 94 }
95 95
96 bool _writeSP() { 96 bool _writeSP() {
97 final SP = const [_CharCode.SP]; 97 final SP = const [_CharCode.SP];
98 return _httpConnection.outputStream.write(SP); 98 return _httpConnection._write(SP);
99 } 99 }
100 100
101 _HttpConnectionBase _httpConnection; 101 _HttpConnectionBase _httpConnection;
102 Map<String, String> _headers; 102 Map<String, String> _headers;
103 103
104 // Length of the content body. If this is set to -1 (default value) 104 // Length of the content body. If this is set to -1 (default value)
105 // when starting to send data chunked transfer encoding will be 105 // when starting to send data chunked transfer encoding will be
106 // used. 106 // used.
107 int _contentLength; 107 int _contentLength;
108 bool _keepAlive; 108 bool _keepAlive;
(...skipping 157 matching lines...) Expand 10 before | Expand all | Expand 10 after
266 } 266 }
267 267
268 bool _streamWriteFrom(List<int> buffer, int offset, int len) { 268 bool _streamWriteFrom(List<int> buffer, int offset, int len) {
269 return _writeList(buffer, offset, len); 269 return _writeList(buffer, offset, len);
270 } 270 }
271 271
272 void _streamClose() { 272 void _streamClose() {
273 _httpConnection._phase = _HttpConnectionBase.PHASE_IDLE; 273 _httpConnection._phase = _HttpConnectionBase.PHASE_IDLE;
274 _state = DONE; 274 _state = DONE;
275 // Stop tracking no pending write events. 275 // Stop tracking no pending write events.
276 _httpConnection.outputStream.onNoPendingWrites = null; 276 _httpConnection._onNoPendingWrites = null;
277 // Ensure that any trailing data is written. 277 // Ensure that any trailing data is written.
278 _writeDone(); 278 _writeDone();
279 // If the connection is closing then close the output stream to 279 // If the connection is closing then close the output stream to
280 // fully close the socket. 280 // fully close the socket.
281 if (_httpConnection._closing) { 281 if (_httpConnection._closing) {
282 _httpConnection.outputStream.close(); 282 _httpConnection._close();
283 } 283 }
284 } 284 }
285 285
286 void _streamSetNoPendingWriteHandler(callback()) { 286 void _streamSetNoPendingWriteHandler(callback()) {
287 if (_state != DONE) { 287 if (_state != DONE) {
288 _httpConnection.outputStream.onNoPendingWrites = callback; 288 _httpConnection._onNoPendingWrites = callback;
289 } 289 }
290 } 290 }
291 291
292 void _streamSetCloseHandler(callback()) { 292 void _streamSetCloseHandler(callback()) {
293 // TODO(sgjesse): Handle this. 293 // TODO(sgjesse): Handle this.
294 } 294 }
295 295
296 void _streamSetErrorHandler(callback(Exception e)) { 296 void _streamSetErrorHandler(callback(Exception e)) {
297 _streamErrorHandler = callback; 297 _streamErrorHandler = callback;
298 } 298 }
(...skipping 48 matching lines...) Expand 10 before | Expand all | Expand 10 after
347 case HttpStatus.SERVICE_UNAVAILABLE: return "Service Unavailable"; 347 case HttpStatus.SERVICE_UNAVAILABLE: return "Service Unavailable";
348 case HttpStatus.GATEWAY_TIMEOUT: return "Gateway Time-out"; 348 case HttpStatus.GATEWAY_TIMEOUT: return "Gateway Time-out";
349 case HttpStatus.HTTP_VERSION_NOT_SUPPORTED: 349 case HttpStatus.HTTP_VERSION_NOT_SUPPORTED:
350 return "Http Version not supported"; 350 return "Http Version not supported";
351 default: return "Status $statusCode"; 351 default: return "Status $statusCode";
352 } 352 }
353 } 353 }
354 354
355 bool _writeHeader() { 355 bool _writeHeader() {
356 List<int> data; 356 List<int> data;
357 OutputStream stream = _httpConnection.outputStream;
358 357
359 // Write status line. 358 // Write status line.
360 stream.write(_Const.HTTP11); 359 _httpConnection._write(_Const.HTTP11);
361 _writeSP(); 360 _writeSP();
362 data = _statusCode.toString().charCodes(); 361 data = _statusCode.toString().charCodes();
363 stream.write(data); 362 _httpConnection._write(data);
364 _writeSP(); 363 _writeSP();
365 data = reasonPhrase.charCodes(); 364 data = reasonPhrase.charCodes();
366 stream.write(data); 365 _httpConnection._write(data);
367 _writeCRLF(); 366 _writeCRLF();
368 367
369 // Determine the value of the "Connection" header 368 // Determine the value of the "Connection" header
370 // based on the keep alive state. 369 // based on the keep alive state.
371 setHeader("Connection", keepAlive ? "keep-alive" : "close"); 370 setHeader("Connection", keepAlive ? "keep-alive" : "close");
372 // Determine the value of the "Transfer-Encoding" header based on 371 // Determine the value of the "Transfer-Encoding" header based on
373 // whether the content length is known. 372 // whether the content length is known.
374 if (_contentLength >= 0) { 373 if (_contentLength >= 0) {
375 setHeader("Content-Length", _contentLength.toString()); 374 setHeader("Content-Length", _contentLength.toString());
376 } else { 375 } else {
(...skipping 102 matching lines...) Expand 10 before | Expand all | Expand 10 after
479 _httpParser = new _HttpParser(); 478 _httpParser = new _HttpParser();
480 479
481 void _connectionEstablished(Socket socket) { 480 void _connectionEstablished(Socket socket) {
482 _socket = socket; 481 _socket = socket;
483 // Register handler for socket events. 482 // Register handler for socket events.
484 _socket.onData = _onData; 483 _socket.onData = _onData;
485 _socket.onClosed = _onClosed; 484 _socket.onClosed = _onClosed;
486 _socket.onError = _onError; 485 _socket.onError = _onError;
487 } 486 }
488 487
489 OutputStream get outputStream() { 488 bool _write(List<int> data, [bool copyBuffer = false]) {
490 return _socket.outputStream; 489 if (!_error) {
490 return _socket.outputStream.write(data, copyBuffer);
491 }
492 }
493
494 bool _writeFrom(List<int> buffer, [int offset, int len]) {
495 if (!_error) {
496 return _socket.outputStream.writeFrom(buffer, offset, len);
497 }
498 }
499
500 bool _close() {
501 _socket.close();
491 } 502 }
492 503
493 void _onData() { 504 void _onData() {
494 int available = _socket.available(); 505 int available = _socket.available();
495 if (available == 0) { 506 if (available == 0) {
496 return; 507 return;
497 } 508 }
498 509
499 ByteArray buffer = new ByteArray(available); 510 ByteArray buffer = new ByteArray(available);
500 int bytesRead = _socket.readList(buffer, 0, available); 511 int bytesRead = _socket.readList(buffer, 0, available);
501 if (bytesRead > 0) { 512 if (bytesRead > 0) {
502 int parsed = _httpParser.writeList(buffer, 0, bytesRead); 513 int parsed = _httpParser.writeList(buffer, 0, bytesRead);
503 if (parsed != bytesRead) { 514 if (parsed != bytesRead) {
504 // TODO(sgjesse): Error handling. 515 // TODO(sgjesse): Error handling.
505 _socket.close(); 516 _socket.close();
506 } 517 }
507 } 518 }
508 } 519 }
509 520
510 void _onClosed() { 521 void _onClosed() {
Anders Johnsen 2012/04/02 08:42:32 Could the socket be closed normally from the clien
Søren Gjesse 2012/04/02 09:14:31 The client can half-close the socket when finished
511 if (_phase != PHASE_IDLE) { 522 if (_phase != PHASE_IDLE) {
512 // Client closed socket for writing. Socket should still be open 523 // Client closed socket for writing. Socket should still be open
513 // for writing the response. 524 // for writing the response.
514 _closing = true; 525 _closing = true;
515 } else { 526 } else {
516 // The connection is currently not used by any request just close it. 527 // The connection is currently not used by any request just close it.
517 _socket.close(); 528 _socket.close();
518 } 529 }
519 if (_onDisconnectCallback != null) _onDisconnectCallback(); 530 if (_onDisconnectCallback != null) _onDisconnectCallback();
520 } 531 }
521 532
522 void _onError(Exception e) { 533 void _onError(Exception e) {
523 // If an error occurs, make sure to close the socket if one is associated. 534 // If an error occurs, make sure to close the socket if one is associated.
535 _error = true;
524 if (_socket != null) { 536 if (_socket != null) {
525 _socket.close(); 537 _socket.close();
526 } 538 }
527 if (_onErrorCallback != null) { 539 if (_onErrorCallback != null) {
528 _onErrorCallback(e); 540 _onErrorCallback(e);
529 } 541 }
530 _propagateError(e); 542 _propagateError(e);
531 } 543 }
532 544
533 abstract void _propagateError(Exception e); 545 abstract void _propagateError(Exception e);
534 546
535 void set onDisconnect(void callback()) { 547 void set onDisconnect(void callback()) {
536 _onDisconnectCallback = callback; 548 _onDisconnectCallback = callback;
537 } 549 }
538 550
539 void set onError(void callback(Exception e)) { 551 void set onError(void callback(Exception e)) {
540 _onErrorCallback = callback; 552 _onErrorCallback = callback;
541 } 553 }
542 554
555 void set _onNoPendingWrites(void callback()) {
556 if (!_error) {
557 _socket.outputStream.onNoPendingWrites = callback;
558 }
559 }
560
543 int hashCode() => _socket.hashCode(); 561 int hashCode() => _socket.hashCode();
544 562
545 int _phase; 563 int _phase;
546 Socket _socket; 564 Socket _socket;
547 bool _closing = false; // Is the socket closed by the client? 565 bool _closing = false; // Is the socket closed by the client?
566 bool _error = false; // Is the socket closed due to an error?
548 _HttpParser _httpParser; 567 _HttpParser _httpParser;
549 568
550 Queue _sendBuffers; 569 Queue _sendBuffers;
551 570
552 Function _onDisconnectCallback; 571 Function _onDisconnectCallback;
553 Function _onErrorCallback; 572 Function _onErrorCallback;
554 } 573 }
555 574
556 575
557 // HTTP server connection over a socket. 576 // HTTP server connection over a socket.
(...skipping 190 matching lines...) Expand 10 before | Expand all | Expand 10 after
748 return _write(buffer, copyBuffer); 767 return _write(buffer, copyBuffer);
749 } 768 }
750 769
751 bool _streamWriteFrom(List<int> buffer, int offset, int len) { 770 bool _streamWriteFrom(List<int> buffer, int offset, int len) {
752 return _writeList(buffer, offset, len); 771 return _writeList(buffer, offset, len);
753 } 772 }
754 773
755 void _streamClose() { 774 void _streamClose() {
756 _state = DONE; 775 _state = DONE;
757 // Stop tracking no pending write events. 776 // Stop tracking no pending write events.
758 _httpConnection.outputStream.onNoPendingWrites = null; 777 _httpConnection._onNoPendingWrites = null;
759 // Ensure that any trailing data is written. 778 // Ensure that any trailing data is written.
760 _writeDone(); 779 _writeDone();
761 // If the connection is closing then close the output stream to 780 // If the connection is closing then close the output stream to
762 // fully close the socket. 781 // fully close the socket.
763 if (_httpConnection._closing) { 782 if (_httpConnection._closing) {
764 _httpConnection.outputStream.close(); 783 _httpConnection._close();
765 } 784 }
766 } 785 }
767 786
768 void _streamSetNoPendingWriteHandler(callback()) { 787 void _streamSetNoPendingWriteHandler(callback()) {
769 if (_state != DONE) { 788 if (_state != DONE) {
770 _httpConnection.outputStream.onNoPendingWrites = callback; 789 _httpConnection._onNoPendingWrites = callback;
771 } 790 }
772 } 791 }
773 792
774 void _streamSetCloseHandler(callback()) { 793 void _streamSetCloseHandler(callback()) {
775 // TODO(sgjesse): Handle this. 794 // TODO(sgjesse): Handle this.
776 } 795 }
777 796
778 void _streamSetErrorHandler(callback(Exception e)) { 797 void _streamSetErrorHandler(callback(Exception e)) {
779 _streamErrorHandler = callback; 798 _streamErrorHandler = callback;
780 } 799 }
781 800
782 void _writeHeader() { 801 void _writeHeader() {
783 List<int> data; 802 List<int> data;
784 OutputStream stream = _httpConnection.outputStream;
785 803
786 // Write request line. 804 // Write request line.
787 data = _method.toString().charCodes(); 805 data = _method.toString().charCodes();
788 stream.write(data); 806 _httpConnection._write(data);
789 _writeSP(); 807 _writeSP();
790 data = _uri.toString().charCodes(); 808 data = _uri.toString().charCodes();
791 stream.write(data); 809 _httpConnection._write(data);
792 _writeSP(); 810 _writeSP();
793 stream.write(_Const.HTTP11); 811 _httpConnection._write(_Const.HTTP11);
794 _writeCRLF(); 812 _writeCRLF();
795 813
796 // Determine the value of the "Connection" header 814 // Determine the value of the "Connection" header
797 // based on the keep alive state. 815 // based on the keep alive state.
798 setHeader("Connection", keepAlive ? "keep-alive" : "close"); 816 setHeader("Connection", keepAlive ? "keep-alive" : "close");
799 // Determine the value of the "Transfer-Encoding" header based on 817 // Determine the value of the "Transfer-Encoding" header based on
800 // whether the content length is known. 818 // whether the content length is known.
801 if (_contentLength >= 0) { 819 if (_contentLength >= 0) {
802 setHeader("Content-Length", _contentLength.toString()); 820 setHeader("Content-Length", _contentLength.toString());
803 } else { 821 } else {
(...skipping 390 matching lines...) Expand 10 before | Expand all | Expand 10 after
1194 sockets.addFirst(socketConn); 1212 sockets.addFirst(socketConn);
1195 socketConn._markReturned(); 1213 socketConn._markReturned();
1196 } 1214 }
1197 1215
1198 Function _onOpen; 1216 Function _onOpen;
1199 Map<String, Queue<_SocketConnection>> _openSockets; 1217 Map<String, Queue<_SocketConnection>> _openSockets;
1200 Set<_SocketConnection> _activeSockets; 1218 Set<_SocketConnection> _activeSockets;
1201 Timer _evictionTimer; 1219 Timer _evictionTimer;
1202 bool _shutdown; // Has this HTTP client been shutdown? 1220 bool _shutdown; // Has this HTTP client been shutdown?
1203 } 1221 }
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