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 |