| 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 part of dart.io; | 5 part of dart.io; |
| 6 | 6 |
| 7 // The close queue handles graceful closing of HTTP connections. When | 7 // The close queue handles graceful closing of HTTP connections. When |
| 8 // a connection is added to the queue it will enter a wait state | 8 // a connection is added to the queue it will enter a wait state |
| 9 // waiting for all data written and possibly socket shutdown from | 9 // waiting for all data written and possibly socket shutdown from |
| 10 // peer. | 10 // peer. |
| (...skipping 109 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 120 headers.add(HttpHeaders.CONNECTION, "keep-alive"); | 120 headers.add(HttpHeaders.CONNECTION, "keep-alive"); |
| 121 } | 121 } |
| 122 } | 122 } |
| 123 | 123 |
| 124 | 124 |
| 125 bool _write(List<int> data, bool copyBuffer) { | 125 bool _write(List<int> data, bool copyBuffer) { |
| 126 if (_headResponse) return true; | 126 if (_headResponse) return true; |
| 127 _ensureHeadersSent(); | 127 _ensureHeadersSent(); |
| 128 bool allWritten = true; | 128 bool allWritten = true; |
| 129 if (data.length > 0) { | 129 if (data.length > 0) { |
| 130 if (_headers.contentLength < 0) { | 130 if (_headers.chunkedTransferEncoding) { |
| 131 // Write chunk size if transfer encoding is chunked. | 131 // Write chunk size if transfer encoding is chunked. |
| 132 _writeHexString(data.length); | 132 _writeHexString(data.length); |
| 133 _writeCRLF(); | 133 _writeCRLF(); |
| 134 _httpConnection._write(data, copyBuffer); | 134 _httpConnection._write(data, copyBuffer); |
| 135 allWritten = _writeCRLF(); | 135 allWritten = _writeCRLF(); |
| 136 } else { | 136 } else { |
| 137 _updateContentLength(data.length); | 137 _updateContentLength(data.length); |
| 138 allWritten = _httpConnection._write(data, copyBuffer); | 138 allWritten = _httpConnection._write(data, copyBuffer); |
| 139 } | 139 } |
| 140 } | 140 } |
| 141 return allWritten; | 141 return allWritten; |
| 142 } | 142 } |
| 143 | 143 |
| 144 bool _writeList(List<int> data, int offset, int count) { | 144 bool _writeList(List<int> data, int offset, int count) { |
| 145 if (_headResponse) return true; | 145 if (_headResponse) return true; |
| 146 _ensureHeadersSent(); | 146 _ensureHeadersSent(); |
| 147 bool allWritten = true; | 147 bool allWritten = true; |
| 148 if (count > 0) { | 148 if (count > 0) { |
| 149 if (_headers.contentLength < 0) { | 149 if (_headers.chunkedTransferEncoding) { |
| 150 // Write chunk size if transfer encoding is chunked. | 150 // Write chunk size if transfer encoding is chunked. |
| 151 _writeHexString(count); | 151 _writeHexString(count); |
| 152 _writeCRLF(); | 152 _writeCRLF(); |
| 153 _httpConnection._writeFrom(data, offset, count); | 153 _httpConnection._writeFrom(data, offset, count); |
| 154 allWritten = _writeCRLF(); | 154 allWritten = _writeCRLF(); |
| 155 } else { | 155 } else { |
| 156 _updateContentLength(count); | 156 _updateContentLength(count); |
| 157 allWritten = _httpConnection._writeFrom(data, offset, count); | 157 allWritten = _httpConnection._writeFrom(data, offset, count); |
| 158 } | 158 } |
| 159 } | 159 } |
| 160 return allWritten; | 160 return allWritten; |
| 161 } | 161 } |
| 162 | 162 |
| 163 bool _writeDone() { | 163 bool _writeDone() { |
| 164 bool allWritten = true; | 164 bool allWritten = true; |
| 165 if (_headers.contentLength < 0) { | 165 if (_headers.chunkedTransferEncoding) { |
| 166 // Terminate the content if transfer encoding is chunked. | 166 // Terminate the content if transfer encoding is chunked. |
| 167 allWritten = _httpConnection._write(_Const.END_CHUNKED); | 167 allWritten = _httpConnection._write(_Const.END_CHUNKED); |
| 168 } else { | 168 } else { |
| 169 if (!_headResponse && _bodyBytesWritten < _headers.contentLength) { | 169 if (!_headResponse && _bodyBytesWritten < _headers.contentLength) { |
| 170 throw new HttpException("Sending less than specified content length"); | 170 throw new HttpException("Sending less than specified content length"); |
| 171 } | 171 } |
| 172 assert(_headResponse || _bodyBytesWritten == _headers.contentLength); | 172 assert(_headResponse || _bodyBytesWritten == _headers.contentLength); |
| 173 } | 173 } |
| 174 return allWritten; | 174 return allWritten; |
| 175 } | 175 } |
| 176 | 176 |
| 177 bool _writeHeaders() { | 177 bool _writeHeaders() { |
| 178 _headers._mutable = false; | |
| 179 _headers._write(_httpConnection); | 178 _headers._write(_httpConnection); |
| 180 // Terminate header. | 179 // Terminate header. |
| 181 return _writeCRLF(); | 180 return _writeCRLF(); |
| 182 } | 181 } |
| 183 | 182 |
| 184 bool _writeHexString(int x) { | 183 bool _writeHexString(int x) { |
| 185 final List<int> hexDigits = [0x30, 0x31, 0x32, 0x33, 0x34, | 184 final List<int> hexDigits = [0x30, 0x31, 0x32, 0x33, 0x34, |
| 186 0x35, 0x36, 0x37, 0x38, 0x39, | 185 0x35, 0x36, 0x37, 0x38, 0x39, |
| 187 0x41, 0x42, 0x43, 0x44, 0x45, 0x46]; | 186 0x41, 0x42, 0x43, 0x44, 0x45, 0x46]; |
| 188 List<int> hex = new Uint8List(10); | 187 List<int> hex = new Uint8List(10); |
| (...skipping 163 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 352 if (sessionId != null) { | 351 if (sessionId != null) { |
| 353 var sessionManager = _httpConnection._server._sessionManager; | 352 var sessionManager = _httpConnection._server._sessionManager; |
| 354 _session = sessionManager.getSession(sessionId); | 353 _session = sessionManager.getSession(sessionId); |
| 355 if (_session != null) { | 354 if (_session != null) { |
| 356 _session._markSeen(); | 355 _session._markSeen(); |
| 357 } | 356 } |
| 358 } | 357 } |
| 359 } | 358 } |
| 360 | 359 |
| 361 // Prepare for receiving data. | 360 // Prepare for receiving data. |
| 362 _headers._mutable = false; | |
| 363 _buffer = new _BufferList(); | 361 _buffer = new _BufferList(); |
| 364 } | 362 } |
| 365 | 363 |
| 366 void _onDataReceived(List<int> data) { | 364 void _onDataReceived(List<int> data) { |
| 367 _buffer.add(data); | 365 _buffer.add(data); |
| 368 if (_inputStream != null) _inputStream._dataReceived(); | 366 if (_inputStream != null) _inputStream._dataReceived(); |
| 369 } | 367 } |
| 370 | 368 |
| 371 void _onDataEnd() { | 369 void _onDataEnd() { |
| 372 if (_inputStream != null) { | 370 if (_inputStream != null) { |
| (...skipping 210 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 583 _httpConnection._write(_Const.HTTP10); | 581 _httpConnection._write(_Const.HTTP10); |
| 584 } | 582 } |
| 585 _writeSP(); | 583 _writeSP(); |
| 586 data = _statusCode.toString().charCodes; | 584 data = _statusCode.toString().charCodes; |
| 587 _httpConnection._write(data); | 585 _httpConnection._write(data); |
| 588 _writeSP(); | 586 _writeSP(); |
| 589 data = reasonPhrase.charCodes; | 587 data = reasonPhrase.charCodes; |
| 590 _httpConnection._write(data); | 588 _httpConnection._write(data); |
| 591 _writeCRLF(); | 589 _writeCRLF(); |
| 592 | 590 |
| 593 // Determine the value of the "Transfer-Encoding" header based on | |
| 594 // whether the content length is known. HTTP/1.0 does not support | |
| 595 // chunked. | |
| 596 if (_headers.contentLength < 0 && _protocolVersion == "1.1") { | |
| 597 _headers.set(HttpHeaders.TRANSFER_ENCODING, "chunked"); | |
| 598 } | |
| 599 | |
| 600 var session = _httpConnection._request._session; | 591 var session = _httpConnection._request._session; |
| 601 if (session != null && !session._destroyed) { | 592 if (session != null && !session._destroyed) { |
| 602 // Make sure we only send the current session id. | 593 // Make sure we only send the current session id. |
| 603 bool found = false; | 594 bool found = false; |
| 604 for (int i = 0; i < cookies.length; i++) { | 595 for (int i = 0; i < cookies.length; i++) { |
| 605 if (cookies[i].name.toUpperCase() == _DART_SESSION_ID) { | 596 if (cookies[i].name.toUpperCase() == _DART_SESSION_ID) { |
| 606 cookies[i].value = session.id; | 597 cookies[i].value = session.id; |
| 607 cookies[i].httpOnly = true; | 598 cookies[i].httpOnly = true; |
| 608 found = true; | 599 found = true; |
| 609 break; | 600 break; |
| 610 } | 601 } |
| 611 } | 602 } |
| 612 if (!found) { | 603 if (!found) { |
| 613 cookies.add(new Cookie(_DART_SESSION_ID, session.id)..httpOnly = true); | 604 cookies.add(new Cookie(_DART_SESSION_ID, session.id)..httpOnly = true); |
| 614 } | 605 } |
| 615 } | 606 } |
| 616 // Add all the cookies set to the headers. | 607 // Add all the cookies set to the headers. |
| 617 if (_cookies != null) { | 608 if (_cookies != null) { |
| 618 _cookies.forEach((cookie) { | 609 _cookies.forEach((cookie) { |
| 619 _headers.add("set-cookie", cookie); | 610 _headers.add("set-cookie", cookie); |
| 620 }); | 611 }); |
| 621 } | 612 } |
| 622 | 613 |
| 623 // Write headers. | 614 // Write headers. |
| 615 _headers._finalize(_protocolVersion); |
| 624 bool allWritten = _writeHeaders(); | 616 bool allWritten = _writeHeaders(); |
| 625 _state = _HttpRequestResponseBase.HEADER_SENT; | 617 _state = _HttpRequestResponseBase.HEADER_SENT; |
| 626 return allWritten; | 618 return allWritten; |
| 627 } | 619 } |
| 628 | 620 |
| 629 int _statusCode; // Response status code. | 621 int _statusCode; // Response status code. |
| 630 String _reasonPhrase; // Response reason phrase. | 622 String _reasonPhrase; // Response reason phrase. |
| 631 _HttpOutputStream _outputStream; | 623 _HttpOutputStream _outputStream; |
| 632 Function _streamErrorHandler; | 624 Function _streamErrorHandler; |
| 633 } | 625 } |
| (...skipping 610 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1244 } | 1236 } |
| 1245 data = path.charCodes; | 1237 data = path.charCodes; |
| 1246 } else { | 1238 } else { |
| 1247 data = _uri.toString().charCodes; | 1239 data = _uri.toString().charCodes; |
| 1248 } | 1240 } |
| 1249 _httpConnection._write(data); | 1241 _httpConnection._write(data); |
| 1250 _writeSP(); | 1242 _writeSP(); |
| 1251 _httpConnection._write(_Const.HTTP11); | 1243 _httpConnection._write(_Const.HTTP11); |
| 1252 _writeCRLF(); | 1244 _writeCRLF(); |
| 1253 | 1245 |
| 1254 // Determine the value of the "Transfer-Encoding" header based on | |
| 1255 // whether the content length is known. If there is no content | |
| 1256 // neither "Content-Length" nor "Transfer-Encoding" is set. | |
| 1257 if (_headers.contentLength < 0) { | |
| 1258 _headers.set(HttpHeaders.TRANSFER_ENCODING, "chunked"); | |
| 1259 } | |
| 1260 | |
| 1261 // Add the cookies to the headers. | 1246 // Add the cookies to the headers. |
| 1262 if (_cookies != null) { | 1247 if (_cookies != null) { |
| 1263 StringBuffer sb = new StringBuffer(); | 1248 StringBuffer sb = new StringBuffer(); |
| 1264 for (int i = 0; i < _cookies.length; i++) { | 1249 for (int i = 0; i < _cookies.length; i++) { |
| 1265 if (i > 0) sb.add("; "); | 1250 if (i > 0) sb.add("; "); |
| 1266 sb.add(_cookies[i].name); | 1251 sb.add(_cookies[i].name); |
| 1267 sb.add("="); | 1252 sb.add("="); |
| 1268 sb.add(_cookies[i].value); | 1253 sb.add(_cookies[i].value); |
| 1269 } | 1254 } |
| 1270 _headers.add("cookie", sb.toString()); | 1255 _headers.add("cookie", sb.toString()); |
| 1271 } | 1256 } |
| 1272 | 1257 |
| 1273 // Write headers. | 1258 // Write headers. |
| 1259 _headers._finalize("1.1"); |
| 1274 _writeHeaders(); | 1260 _writeHeaders(); |
| 1275 _state = _HttpRequestResponseBase.HEADER_SENT; | 1261 _state = _HttpRequestResponseBase.HEADER_SENT; |
| 1276 } | 1262 } |
| 1277 | 1263 |
| 1278 String _method; | 1264 String _method; |
| 1279 Uri _uri; | 1265 Uri _uri; |
| 1280 _HttpClientConnection _connection; | 1266 _HttpClientConnection _connection; |
| 1281 _HttpOutputStream _outputStream; | 1267 _HttpOutputStream _outputStream; |
| 1282 Function _streamErrorHandler; | 1268 Function _streamErrorHandler; |
| 1283 bool _emptyBody = true; | 1269 bool _emptyBody = true; |
| (...skipping 45 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1329 void _onResponseReceived(int statusCode, | 1315 void _onResponseReceived(int statusCode, |
| 1330 String reasonPhrase, | 1316 String reasonPhrase, |
| 1331 String version, | 1317 String version, |
| 1332 _HttpHeaders headers, | 1318 _HttpHeaders headers, |
| 1333 bool hasBody) { | 1319 bool hasBody) { |
| 1334 _statusCode = statusCode; | 1320 _statusCode = statusCode; |
| 1335 _reasonPhrase = reasonPhrase; | 1321 _reasonPhrase = reasonPhrase; |
| 1336 _headers = headers; | 1322 _headers = headers; |
| 1337 | 1323 |
| 1338 // Prepare for receiving data. | 1324 // Prepare for receiving data. |
| 1339 _headers._mutable = false; | |
| 1340 _buffer = new _BufferList(); | 1325 _buffer = new _BufferList(); |
| 1341 if (isRedirect && _connection.followRedirects) { | 1326 if (isRedirect && _connection.followRedirects) { |
| 1342 if (_connection._redirects == null || | 1327 if (_connection._redirects == null || |
| 1343 _connection._redirects.length < _connection.maxRedirects) { | 1328 _connection._redirects.length < _connection.maxRedirects) { |
| 1344 // Check the location header. | 1329 // Check the location header. |
| 1345 List<String> location = headers[HttpHeaders.LOCATION]; | 1330 List<String> location = headers[HttpHeaders.LOCATION]; |
| 1346 if (location == null || location.length > 1) { | 1331 if (location == null || location.length > 1) { |
| 1347 throw new RedirectException("Invalid redirect", | 1332 throw new RedirectException("Invalid redirect", |
| 1348 _connection._redirects); | 1333 _connection._redirects); |
| 1349 } | 1334 } |
| (...skipping 965 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2315 | 2300 |
| 2316 | 2301 |
| 2317 class _RedirectInfo implements RedirectInfo { | 2302 class _RedirectInfo implements RedirectInfo { |
| 2318 const _RedirectInfo(int this.statusCode, | 2303 const _RedirectInfo(int this.statusCode, |
| 2319 String this.method, | 2304 String this.method, |
| 2320 Uri this.location); | 2305 Uri this.location); |
| 2321 final int statusCode; | 2306 final int statusCode; |
| 2322 final String method; | 2307 final String method; |
| 2323 final Uri location; | 2308 final Uri location; |
| 2324 } | 2309 } |
| OLD | NEW |