Chromium Code Reviews| 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 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 Loading... | |
| 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 Loading... | |
| 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 Loading... | |
| 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 Loading... | |
| 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 Loading... | |
| 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 Loading... | |
| 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 Loading... | |
| 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 Loading... | |
| 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 Loading... | |
| 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 } |
| OLD | NEW |