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

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

Issue 10232006: Check the state of the HTTP request and response when handling headers (Closed) Base URL: https://dart.googlecode.com/svn/branches/bleeding_edge/dart
Patch Set: Reverted unintentional edit 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 | « runtime/bin/http.dart ('k') | tests/standalone/src/io/HttpContentLengthTest.dart » ('j') | 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 _HttpHeaders implements HttpHeaders { 5 class _HttpHeaders implements HttpHeaders {
6 _HttpHeaders() : _headers = new Map<String, List<String>>(); 6 _HttpHeaders() : _headers = new Map<String, List<String>>();
7 7
8 List<String> operator[](String name) { 8 List<String> operator[](String name) {
9 name = name.toLowerCase(); 9 name = name.toLowerCase();
10 return _headers[name]; 10 return _headers[name];
11 } 11 }
12 12
13 String value(String name) { 13 String value(String name) {
14 name = name.toLowerCase(); 14 name = name.toLowerCase();
15 List<String> values = _headers[name]; 15 List<String> values = _headers[name];
16 if (values == null) return null; 16 if (values == null) return null;
17 if (values.length > 1) { 17 if (values.length > 1) {
18 throw new HttpException("More than one value for header $name"); 18 throw new HttpException("More than one value for header $name");
19 } 19 }
20 return values[0]; 20 return values[0];
21 } 21 }
22 22
23 void add(String name, Object value) { 23 void add(String name, Object value) {
24 _checkMutable();
24 if (value is List) { 25 if (value is List) {
25 for (int i = 0; i < value.length; i++) { 26 for (int i = 0; i < value.length; i++) {
26 _add(name, value[i]); 27 _add(name, value[i]);
27 } 28 }
28 } else { 29 } else {
29 _add(name, value); 30 _add(name, value);
30 } 31 }
31 } 32 }
32 33
33 void set(String name, Object value) { 34 void set(String name, Object value) {
35 _checkMutable();
34 removeAll(name); 36 removeAll(name);
35 add(name, value); 37 add(name, value);
36 } 38 }
37 39
38 void remove(String name, Object value) { 40 void remove(String name, Object value) {
41 _checkMutable();
39 name = name.toLowerCase(); 42 name = name.toLowerCase();
40 List<String> values = _headers[name]; 43 List<String> values = _headers[name];
41 if (values != null) { 44 if (values != null) {
42 int index = values.indexOf(value); 45 int index = values.indexOf(value);
43 if (index != -1) { 46 if (index != -1) {
44 values.removeRange(index, 1); 47 values.removeRange(index, 1);
45 } 48 }
46 } 49 }
47 } 50 }
48 51
49 void removeAll(String name) { 52 void removeAll(String name) {
53 _checkMutable();
50 name = name.toLowerCase(); 54 name = name.toLowerCase();
51 _headers.remove(name); 55 _headers.remove(name);
52 } 56 }
53 57
54 String get host() => _host; 58 String get host() => _host;
59
55 void set host(String host) { 60 void set host(String host) {
61 _checkMutable();
56 _host = host; 62 _host = host;
57 _updateHostHeader(); 63 _updateHostHeader();
58 } 64 }
59 65
60 int get port() => _port; 66 int get port() => _port;
67
61 void set port(int port) { 68 void set port(int port) {
69 _checkMutable();
62 _port = port; 70 _port = port;
63 _updateHostHeader(); 71 _updateHostHeader();
64 } 72 }
65 73
66 Date get date() { 74 Date get date() {
67 List<String> values = _headers["date"]; 75 List<String> values = _headers["date"];
68 if (values != null) { 76 if (values != null) {
69 try { 77 try {
70 return _HttpUtils.parseDate(values[0]); 78 return _HttpUtils.parseDate(values[0]);
71 } catch (Exception e) { 79 } catch (Exception e) {
72 return null; 80 return null;
73 } 81 }
74 } 82 }
75 return null; 83 return null;
76 } 84 }
77 85
78 void set date(Date date) { 86 void set date(Date date) {
87 _checkMutable();
79 // Format "Date" header with date in Greenwich Mean Time (GMT). 88 // Format "Date" header with date in Greenwich Mean Time (GMT).
80 String formatted = 89 String formatted =
81 _HttpUtils.formatDate(expires.changeTimeZone(new TimeZone.utc())); 90 _HttpUtils.formatDate(expires.changeTimeZone(new TimeZone.utc()));
82 _set("date", formatted); 91 _set("date", formatted);
83 } 92 }
84 93
85 Date get expires() { 94 Date get expires() {
86 List<String> values = _headers["expires"]; 95 List<String> values = _headers["expires"];
87 if (values != null) { 96 if (values != null) {
88 try { 97 try {
89 return _HttpUtils.parseDate(values[0]); 98 return _HttpUtils.parseDate(values[0]);
90 } catch (Exception e) { 99 } catch (Exception e) {
91 return null; 100 return null;
92 } 101 }
93 } 102 }
94 return null; 103 return null;
95 } 104 }
96 105
97 void set expires(Date expires) { 106 void set expires(Date expires) {
107 _checkMutable();
98 // Format "Expires" header with date in Greenwich Mean Time (GMT). 108 // Format "Expires" header with date in Greenwich Mean Time (GMT).
99 String formatted = 109 String formatted =
100 _HttpUtils.formatDate(expires.changeTimeZone(new TimeZone.utc())); 110 _HttpUtils.formatDate(expires.changeTimeZone(new TimeZone.utc()));
101 _set("expires", formatted); 111 _set("expires", formatted);
102 } 112 }
103 113
104 void _add(String name, Object value) { 114 void _add(String name, Object value) {
105 // TODO(sgjesse): Add immutable state throw HttpException is immutable. 115 // TODO(sgjesse): Add immutable state throw HttpException is immutable.
106 if (name.toLowerCase() == "date") { 116 if (name.toLowerCase() == "date") {
107 if (value is Date) { 117 if (value is Date) {
(...skipping 44 matching lines...) Expand 10 before | Expand all | Expand 10 after
152 } 162 }
153 } 163 }
154 164
155 void _set(String name, String value) { 165 void _set(String name, String value) {
156 name = name.toLowerCase(); 166 name = name.toLowerCase();
157 List<String> values = new List<String>(); 167 List<String> values = new List<String>();
158 _headers[name] = values; 168 _headers[name] = values;
159 values.add(value); 169 values.add(value);
160 } 170 }
161 171
172 _checkMutable() {
173 if (!_mutable) throw new HttpException("HTTP headers are not mutable");
174 }
175
162 _updateHostHeader() { 176 _updateHostHeader() {
163 bool defaultPort = _port == null || _port == HttpClient.DEFAULT_HTTP_PORT; 177 bool defaultPort = _port == null || _port == HttpClient.DEFAULT_HTTP_PORT;
164 String portPart = defaultPort ? "" : ":$_port"; 178 String portPart = defaultPort ? "" : ":$_port";
165 _set("host", "$host$portPart"); 179 _set("host", "$host$portPart");
166 } 180 }
167 181
168 _write(_HttpConnectionBase connection) { 182 _write(_HttpConnectionBase connection) {
169 final COLONSP = const [_CharCode.COLON, _CharCode.SP]; 183 final COLONSP = const [_CharCode.COLON, _CharCode.SP];
170 final COMMASP = const [_CharCode.COMMA, _CharCode.SP]; 184 final COMMASP = const [_CharCode.COMMA, _CharCode.SP];
171 final CRLF = const [_CharCode.CR, _CharCode.LF]; 185 final CRLF = const [_CharCode.CR, _CharCode.LF];
(...skipping 24 matching lines...) Expand all
196 if (i > 0) { 210 if (i > 0) {
197 sb.add(": "); 211 sb.add(": ");
198 } 212 }
199 sb.add(values[i]); 213 sb.add(values[i]);
200 } 214 }
201 sb.add("\n"); 215 sb.add("\n");
202 }); 216 });
203 return sb.toString(); 217 return sb.toString();
204 } 218 }
205 219
220 bool _mutable = true; // Are the headers currently mutable?
206 Map<String, List<String>> _headers; 221 Map<String, List<String>> _headers;
207 222
208 String _host; 223 String _host;
209 int _port; 224 int _port;
210 } 225 }
211 226
212 227
213 class _HttpRequestResponseBase { 228 class _HttpRequestResponseBase {
229 final int START = 0;
230 final int HEADER_SENT = 1;
231 final int DONE = 2;
232
214 _HttpRequestResponseBase(_HttpConnectionBase this._httpConnection) 233 _HttpRequestResponseBase(_HttpConnectionBase this._httpConnection)
215 : _contentLength = -1, 234 : _headers = new _HttpHeaders() {
216 _headers = new _HttpHeaders(); 235 _state = START;
236 }
217 237
218 int get contentLength() => _contentLength; 238 int get contentLength() => _contentLength;
219 HttpHeaders get headers() => _headers; 239 HttpHeaders get headers() => _headers;
220 240
221 bool _write(List<int> data, bool copyBuffer) { 241 bool _write(List<int> data, bool copyBuffer) {
242 _ensureHeadersSent();
222 bool allWritten = true; 243 bool allWritten = true;
223 if (data.length > 0) { 244 if (data.length > 0) {
224 if (_contentLength < 0) { 245 if (_contentLength < 0) {
225 // Write chunk size if transfer encoding is chunked. 246 // Write chunk size if transfer encoding is chunked.
226 _writeHexString(data.length); 247 _writeHexString(data.length);
227 _writeCRLF(); 248 _writeCRLF();
228 _httpConnection._write(data, copyBuffer); 249 _httpConnection._write(data, copyBuffer);
229 allWritten = _writeCRLF(); 250 allWritten = _writeCRLF();
230 } else { 251 } else {
252 _checkContentLength(data.length);
231 allWritten = _httpConnection._write(data, copyBuffer); 253 allWritten = _httpConnection._write(data, copyBuffer);
232 } 254 }
233 } 255 }
234 return allWritten; 256 return allWritten;
235 } 257 }
236 258
237 bool _writeList(List<int> data, int offset, int count) { 259 bool _writeList(List<int> data, int offset, int count) {
260 _ensureHeadersSent();
238 bool allWritten = true; 261 bool allWritten = true;
239 if (count > 0) { 262 if (count > 0) {
240 if (_contentLength < 0) { 263 if (_contentLength < 0) {
241 // Write chunk size if transfer encoding is chunked. 264 // Write chunk size if transfer encoding is chunked.
242 _writeHexString(count); 265 _writeHexString(count);
243 _writeCRLF(); 266 _writeCRLF();
244 _httpConnection._writeFrom(data, offset, count); 267 _httpConnection._writeFrom(data, offset, count);
245 allWritten = _writeCRLF(); 268 allWritten = _writeCRLF();
246 } else { 269 } else {
270 _checkContentLength(count);
247 allWritten = _httpConnection._writeFrom(data, offset, count); 271 allWritten = _httpConnection._writeFrom(data, offset, count);
248 } 272 }
249 } 273 }
250 return allWritten; 274 return allWritten;
251 } 275 }
252 276
253 bool _writeDone() { 277 bool _writeDone() {
254 bool allWritten = true; 278 bool allWritten = true;
255 if (_contentLength < 0) { 279 if (_contentLength < 0) {
256 // Terminate the content if transfer encoding is chunked. 280 // Terminate the content if transfer encoding is chunked.
257 allWritten = _httpConnection._write(_Const.END_CHUNKED); 281 allWritten = _httpConnection._write(_Const.END_CHUNKED);
282 } else {
283 if (_bodyBytesWritten < _contentLength) {
284 throw new HttpException("Sending less than specified content length");
285 }
286 assert(_bodyBytesWritten == _contentLength);
258 } 287 }
259 return allWritten; 288 return allWritten;
260 } 289 }
261 290
262 bool _writeHeaders() { 291 bool _writeHeaders() {
292 _headers._mutable = false;
263 _headers._write(_httpConnection); 293 _headers._write(_httpConnection);
264 // Terminate header. 294 // Terminate header.
265 return _writeCRLF(); 295 return _writeCRLF();
266 } 296 }
267 297
268 bool _writeHexString(int x) { 298 bool _writeHexString(int x) {
269 final List<int> hexDigits = [0x30, 0x31, 0x32, 0x33, 0x34, 299 final List<int> hexDigits = [0x30, 0x31, 0x32, 0x33, 0x34,
270 0x35, 0x36, 0x37, 0x38, 0x39, 300 0x35, 0x36, 0x37, 0x38, 0x39,
271 0x41, 0x42, 0x43, 0x44, 0x45, 0x46]; 301 0x41, 0x42, 0x43, 0x44, 0x45, 0x46];
272 ByteArray hex = new ByteArray(10); 302 ByteArray hex = new ByteArray(10);
273 int index = hex.length; 303 int index = hex.length;
274 while (x > 0) { 304 while (x > 0) {
275 index--; 305 index--;
276 hex[index] = hexDigits[x % 16]; 306 hex[index] = hexDigits[x % 16];
277 x = x >> 4; 307 x = x >> 4;
278 } 308 }
279 return _httpConnection._writeFrom(hex, index, hex.length - index); 309 return _httpConnection._writeFrom(hex, index, hex.length - index);
280 } 310 }
281 311
282 bool _writeCRLF() { 312 bool _writeCRLF() {
283 final CRLF = const [_CharCode.CR, _CharCode.LF]; 313 final CRLF = const [_CharCode.CR, _CharCode.LF];
284 return _httpConnection._write(CRLF); 314 return _httpConnection._write(CRLF);
285 } 315 }
286 316
287 bool _writeSP() { 317 bool _writeSP() {
288 final SP = const [_CharCode.SP]; 318 final SP = const [_CharCode.SP];
289 return _httpConnection._write(SP); 319 return _httpConnection._write(SP);
290 } 320 }
291 321
322 void _ensureHeadersSent() {
323 // Ensure that headers are written.
324 if (_state == START) {
325 _writeHeader();
326 }
327 }
328
329 void _checkContentLength(int bytes) {
330 if (_bodyBytesWritten + bytes > _contentLength) {
331 throw new HttpException("Writing more than specified content length");
332 }
333 _bodyBytesWritten += bytes;
Anders Johnsen 2012/04/26 10:12:50 The "check" method here is mutable. Should we rena
Søren Gjesse 2012/04/26 11:26:40 Good point. Renamed to _updateContentLength.
334 }
335
336 int _state;
337
292 _HttpConnectionBase _httpConnection; 338 _HttpConnectionBase _httpConnection;
293 _HttpHeaders _headers; 339 _HttpHeaders _headers;
294 340
295 // Length of the content body. If this is set to -1 (default value) 341 // Length of the content body. If this is set to -1 (default value)
296 // when starting to send data chunked transfer encoding will be 342 // when starting to send data chunked transfer encoding will be
297 // used. 343 // used.
298 int _contentLength; 344 int _contentLength = -1;
345 // Number of body bytes written. This is only actual body data not
346 // including headers or chunk information of using chinked transfer
347 // encoding.
348 int _bodyBytesWritten = 0;
299 } 349 }
300 350
301 351
302 // Parsed HTTP request providing information on the HTTP headers. 352 // Parsed HTTP request providing information on the HTTP headers.
303 class _HttpRequest extends _HttpRequestResponseBase implements HttpRequest { 353 class _HttpRequest extends _HttpRequestResponseBase implements HttpRequest {
304 _HttpRequest(_HttpConnection connection) : super(connection); 354 _HttpRequest(_HttpConnection connection) : super(connection);
305 355
306 String get method() => _method; 356 String get method() => _method;
307 String get uri() => _uri; 357 String get uri() => _uri;
308 String get path() => _path; 358 String get path() => _path;
(...skipping 11 matching lines...) Expand all
320 _method = method; 370 _method = method;
321 _uri = uri; 371 _uri = uri;
322 _parseRequestUri(uri); 372 _parseRequestUri(uri);
323 } 373 }
324 374
325 void _onHeaderReceived(String name, String value) { 375 void _onHeaderReceived(String name, String value) {
326 _headers.add(name, value); 376 _headers.add(name, value);
327 } 377 }
328 378
329 void _onHeadersComplete() { 379 void _onHeadersComplete() {
380 _headers._mutable = false;
330 // Prepare for receiving data. 381 // Prepare for receiving data.
331 _buffer = new _BufferList(); 382 _buffer = new _BufferList();
332 } 383 }
333 384
334 void _onDataReceived(List<int> data) { 385 void _onDataReceived(List<int> data) {
335 _buffer.add(data); 386 _buffer.add(data);
336 if (_inputStream != null) _inputStream._dataReceived(); 387 if (_inputStream != null) _inputStream._dataReceived();
337 } 388 }
338 389
339 void _onDataEnd() { 390 void _onDataEnd() {
(...skipping 39 matching lines...) Expand 10 before | Expand all | Expand 10 after
379 String _queryString; 430 String _queryString;
380 Map<String, String> _queryParameters; 431 Map<String, String> _queryParameters;
381 _HttpInputStream _inputStream; 432 _HttpInputStream _inputStream;
382 _BufferList _buffer; 433 _BufferList _buffer;
383 Function _streamErrorHandler; 434 Function _streamErrorHandler;
384 } 435 }
385 436
386 437
387 // HTTP response object for sending a HTTP response. 438 // HTTP response object for sending a HTTP response.
388 class _HttpResponse extends _HttpRequestResponseBase implements HttpResponse { 439 class _HttpResponse extends _HttpRequestResponseBase implements HttpResponse {
389 static final int START = 0;
390 static final int HEADERS_SENT = 1;
391 static final int DONE = 2;
392
393 _HttpResponse(_HttpConnection httpConnection) 440 _HttpResponse(_HttpConnection httpConnection)
394 : super(httpConnection), 441 : super(httpConnection),
395 _statusCode = HttpStatus.OK, 442 _statusCode = HttpStatus.OK;
396 _state = START;
397 443
398 void set contentLength(int contentLength) { 444 void set contentLength(int contentLength) {
399 if (_outputStream != null) throw new HttpException("Header already sent"); 445 if (_state >= HEADER_SENT) throw new HttpException("Header already sent");
400 _contentLength = contentLength; 446 _contentLength = contentLength;
401 } 447 }
402 448
403 int get statusCode() => _statusCode; 449 int get statusCode() => _statusCode;
404 void set statusCode(int statusCode) { 450 void set statusCode(int statusCode) {
405 if (_outputStream != null) throw new HttpException("Header already sent"); 451 if (_outputStream != null) throw new HttpException("Header already sent");
406 _statusCode = statusCode; 452 _statusCode = statusCode;
407 } 453 }
408 454
409 String get reasonPhrase() => _findReasonPhrase(_statusCode); 455 String get reasonPhrase() => _findReasonPhrase(_statusCode);
410 void set reasonPhrase(String reasonPhrase) { 456 void set reasonPhrase(String reasonPhrase) {
411 if (_outputStream != null) throw new HttpException("Header already sent"); 457 if (_outputStream != null) throw new HttpException("Header already sent");
412 _reasonPhrase = reasonPhrase; 458 _reasonPhrase = reasonPhrase;
413 } 459 }
414 460
415 OutputStream get outputStream() { 461 OutputStream get outputStream() {
416 if (_state == DONE) throw new HttpException("Response closed"); 462 if (_state == DONE) throw new HttpException("Response closed");
417 if (_outputStream == null) { 463 if (_outputStream == null) {
418 // Ensure that headers are written.
419 if (_state == START) {
420 _writeHeader();
421 }
422 _outputStream = new _HttpOutputStream(this); 464 _outputStream = new _HttpOutputStream(this);
423 } 465 }
424 return _outputStream; 466 return _outputStream;
425 } 467 }
426 468
427 void _responseEnd() { 469 void _responseEnd() {
470 _ensureHeadersSent();
428 _state = DONE; 471 _state = DONE;
429 // Stop tracking no pending write events. 472 // Stop tracking no pending write events.
430 _httpConnection._onNoPendingWrites = null; 473 _httpConnection._onNoPendingWrites = null;
431 // Ensure that any trailing data is written. 474 // Ensure that any trailing data is written.
432 _writeDone(); 475 _writeDone();
433 // Indicate to the connection that the response handling is done. 476 // Indicate to the connection that the response handling is done.
434 _httpConnection._responseDone(); 477 _httpConnection._responseDone();
435 } 478 }
436 479
437 // Delegate functions for the HttpOutputStream implementation. 480 // Delegate functions for the HttpOutputStream implementation.
438 bool _streamWrite(List<int> buffer, bool copyBuffer) { 481 bool _streamWrite(List<int> buffer, bool copyBuffer) {
482 if (_state == DONE) throw new HttpException("Response closed");
439 return _write(buffer, copyBuffer); 483 return _write(buffer, copyBuffer);
440 } 484 }
441 485
442 bool _streamWriteFrom(List<int> buffer, int offset, int len) { 486 bool _streamWriteFrom(List<int> buffer, int offset, int len) {
487 if (_state == DONE) throw new HttpException("Response closed");
443 return _writeList(buffer, offset, len); 488 return _writeList(buffer, offset, len);
444 } 489 }
445 490
446 void _streamClose() { 491 void _streamClose() {
447 _responseEnd(); 492 _responseEnd();
448 } 493 }
449 494
450 void _streamSetNoPendingWriteHandler(callback()) { 495 void _streamSetNoPendingWriteHandler(callback()) {
451 if (_state != DONE) { 496 if (_state != DONE) {
452 _httpConnection._onNoPendingWrites = callback; 497 _httpConnection._onNoPendingWrites = callback;
(...skipping 89 matching lines...) Expand 10 before | Expand all | Expand 10 after
542 // Determine the value of the "Transfer-Encoding" header based on 587 // Determine the value of the "Transfer-Encoding" header based on
543 // whether the content length is known. 588 // whether the content length is known.
544 if (_contentLength >= 0) { 589 if (_contentLength >= 0) {
545 _headers.set("Content-Length", _contentLength.toString()); 590 _headers.set("Content-Length", _contentLength.toString());
546 } else { 591 } else {
547 _headers.set("Transfer-Encoding", "chunked"); 592 _headers.set("Transfer-Encoding", "chunked");
548 } 593 }
549 594
550 // Write headers. 595 // Write headers.
551 bool allWritten = _writeHeaders(); 596 bool allWritten = _writeHeaders();
552 _state = HEADERS_SENT; 597 _state = HEADER_SENT;
553 return allWritten; 598 return allWritten;
554 } 599 }
555 600
556 // Response status code. 601 // Response status code.
557 int _statusCode; 602 int _statusCode;
558 String _reasonPhrase; 603 String _reasonPhrase;
559 String _protocolVersion; 604 String _protocolVersion;
560 bool _persistentConnection; 605 bool _persistentConnection;
561 _HttpOutputStream _outputStream; 606 _HttpOutputStream _outputStream;
562 int _state;
563 Function _streamErrorHandler; 607 Function _streamErrorHandler;
564 } 608 }
565 609
566 610
567 class _HttpInputStream extends _BaseDataInputStream implements InputStream { 611 class _HttpInputStream extends _BaseDataInputStream implements InputStream {
568 _HttpInputStream(_HttpRequestResponseBase this._requestOrResponse) { 612 _HttpInputStream(_HttpRequestResponseBase this._requestOrResponse) {
569 _checkScheduleCallbacks(); 613 _checkScheduleCallbacks();
570 } 614 }
571 615
572 int available() { 616 int available() {
(...skipping 357 matching lines...) Expand 10 before | Expand all | Expand 10 after
930 bool _closeServer = false; 974 bool _closeServer = false;
931 Set<_HttpConnection> _connections; // Set of currently connected clients. 975 Set<_HttpConnection> _connections; // Set of currently connected clients.
932 List<_RequestHandlerRegistration> _handlers; 976 List<_RequestHandlerRegistration> _handlers;
933 Object _defaultHandler; 977 Object _defaultHandler;
934 Function _onError; 978 Function _onError;
935 } 979 }
936 980
937 981
938 class _HttpClientRequest 982 class _HttpClientRequest
939 extends _HttpRequestResponseBase implements HttpClientRequest { 983 extends _HttpRequestResponseBase implements HttpClientRequest {
940 static final int START = 0;
941 static final int HEADERS_SENT = 1;
942 static final int DONE = 2;
943
944 _HttpClientRequest(String this._method, 984 _HttpClientRequest(String this._method,
945 String this._uri, 985 String this._uri,
946 _HttpClientConnection connection) 986 _HttpClientConnection connection)
947 : super(connection), 987 : super(connection) {
948 _state = START {
949 _connection = connection; 988 _connection = connection;
950 // Default GET requests to have no content. 989 // Default GET requests to have no content.
951 if (_method == "GET") { 990 if (_method == "GET") {
952 _contentLength = 0; 991 _contentLength = 0;
953 } 992 }
954 } 993 }
955 994
956 void set contentLength(int contentLength) => _contentLength = contentLength; 995 void set contentLength(int contentLength) {
996 if (_state >= HEADER_SENT) throw new HttpException("Header already sent");
997 _contentLength = contentLength;
998 }
957 999
958 OutputStream get outputStream() { 1000 OutputStream get outputStream() {
959 if (_state == DONE) throw new HttpException("Request closed"); 1001 if (_state == DONE) throw new HttpException("Request closed");
960 if (_outputStream == null) { 1002 if (_outputStream == null) {
961 // Ensure that headers are written.
962 if (_state == START) {
963 _writeHeader();
964 }
965 _outputStream = new _HttpOutputStream(this); 1003 _outputStream = new _HttpOutputStream(this);
966 } 1004 }
967 return _outputStream; 1005 return _outputStream;
968 } 1006 }
969 1007
970 // Delegate functions for the HttpOutputStream implementation. 1008 // Delegate functions for the HttpOutputStream implementation.
971 bool _streamWrite(List<int> buffer, bool copyBuffer) { 1009 bool _streamWrite(List<int> buffer, bool copyBuffer) {
1010 if (_state == DONE) throw new HttpException("Request closed");
972 return _write(buffer, copyBuffer); 1011 return _write(buffer, copyBuffer);
973 } 1012 }
974 1013
975 bool _streamWriteFrom(List<int> buffer, int offset, int len) { 1014 bool _streamWriteFrom(List<int> buffer, int offset, int len) {
1015 if (_state == DONE) throw new HttpException("Request closed");
976 return _writeList(buffer, offset, len); 1016 return _writeList(buffer, offset, len);
977 } 1017 }
978 1018
979 void _streamClose() { 1019 void _streamClose() {
1020 _ensureHeadersSent();
980 _state = DONE; 1021 _state = DONE;
981 // Stop tracking no pending write events. 1022 // Stop tracking no pending write events.
982 _httpConnection._onNoPendingWrites = null; 1023 _httpConnection._onNoPendingWrites = null;
983 // Ensure that any trailing data is written. 1024 // Ensure that any trailing data is written.
984 _writeDone(); 1025 _writeDone();
985 } 1026 }
986 1027
987 void _streamSetNoPendingWriteHandler(callback()) { 1028 void _streamSetNoPendingWriteHandler(callback()) {
988 if (_state != DONE) { 1029 if (_state != DONE) {
989 _httpConnection._onNoPendingWrites = callback; 1030 _httpConnection._onNoPendingWrites = callback;
(...skipping 24 matching lines...) Expand all
1014 // Determine the value of the "Transfer-Encoding" header based on 1055 // Determine the value of the "Transfer-Encoding" header based on
1015 // whether the content length is known. 1056 // whether the content length is known.
1016 if (_contentLength >= 0) { 1057 if (_contentLength >= 0) {
1017 _headers.set("Content-Length", _contentLength.toString()); 1058 _headers.set("Content-Length", _contentLength.toString());
1018 } else { 1059 } else {
1019 _headers.set("Transfer-Encoding", "chunked"); 1060 _headers.set("Transfer-Encoding", "chunked");
1020 } 1061 }
1021 1062
1022 // Write headers. 1063 // Write headers.
1023 _writeHeaders(); 1064 _writeHeaders();
1024 _state = HEADERS_SENT; 1065 _state = HEADER_SENT;
1025 } 1066 }
1026 1067
1027 String _method; 1068 String _method;
1028 String _uri; 1069 String _uri;
1029 _HttpClientConnection _connection; 1070 _HttpClientConnection _connection;
1030 _HttpOutputStream _outputStream; 1071 _HttpOutputStream _outputStream;
1031 int _state;
1032 Function _streamErrorHandler; 1072 Function _streamErrorHandler;
1033 } 1073 }
1034 1074
1035 1075
1036 class _HttpClientResponse 1076 class _HttpClientResponse
1037 extends _HttpRequestResponseBase implements HttpClientResponse { 1077 extends _HttpRequestResponseBase implements HttpClientResponse {
1038 _HttpClientResponse(_HttpClientConnection connection) 1078 _HttpClientResponse(_HttpClientConnection connection)
1039 : super(connection) { 1079 : super(connection) {
1040 _connection = connection; 1080 _connection = connection;
1041 } 1081 }
(...skipping 15 matching lines...) Expand all
1057 void _onResponseStart(int statusCode, String reasonPhrase, String version) { 1097 void _onResponseStart(int statusCode, String reasonPhrase, String version) {
1058 _statusCode = statusCode; 1098 _statusCode = statusCode;
1059 _reasonPhrase = reasonPhrase; 1099 _reasonPhrase = reasonPhrase;
1060 } 1100 }
1061 1101
1062 void _onHeaderReceived(String name, String value) { 1102 void _onHeaderReceived(String name, String value) {
1063 _headers.add(name, value); 1103 _headers.add(name, value);
1064 } 1104 }
1065 1105
1066 void _onHeadersComplete() { 1106 void _onHeadersComplete() {
1107 _headers._mutable = false;
1067 _buffer = new _BufferList(); 1108 _buffer = new _BufferList();
1068 if (_connection._onResponse != null) { 1109 if (_connection._onResponse != null) {
1069 _connection._onResponse(this); 1110 _connection._onResponse(this);
1070 } 1111 }
1071 } 1112 }
1072 1113
1073 void _onDataReceived(List<int> data) { 1114 void _onDataReceived(List<int> data) {
1074 _buffer.add(data); 1115 _buffer.add(data);
1075 if (_inputStream != null) _inputStream._dataReceived(); 1116 if (_inputStream != null) _inputStream._dataReceived();
1076 } 1117 }
(...skipping 342 matching lines...) Expand 10 before | Expand all | Expand 10 after
1419 _activeSockets.remove(socketConn); 1460 _activeSockets.remove(socketConn);
1420 sockets.addFirst(socketConn); 1461 sockets.addFirst(socketConn);
1421 } 1462 }
1422 1463
1423 Function _onOpen; 1464 Function _onOpen;
1424 Map<String, Queue<_SocketConnection>> _openSockets; 1465 Map<String, Queue<_SocketConnection>> _openSockets;
1425 Set<_SocketConnection> _activeSockets; 1466 Set<_SocketConnection> _activeSockets;
1426 Timer _evictionTimer; 1467 Timer _evictionTimer;
1427 bool _shutdown; // Has this HTTP client been shutdown? 1468 bool _shutdown; // Has this HTTP client been shutdown?
1428 } 1469 }
OLDNEW
« no previous file with comments | « runtime/bin/http.dart ('k') | tests/standalone/src/io/HttpContentLengthTest.dart » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698