| 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 | 5 |
| 6 class _HttpIncoming extends StreamController<List<int>> { | 6 class _HttpIncoming extends StreamController<List<int>> { |
| 7 final Function _pause; | 7 final Function _pause; |
| 8 final Function _resume; | 8 final Function _resume; |
| 9 bool _ignore = false; | 9 bool _ignore = false; |
| 10 final SignalCompleter _dataCompleter = new SignalCompleter(); | 10 final SignalCompleter _dataCompleter = new SignalCompleter(); |
| (...skipping 48 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 59 super.close(); | 59 super.close(); |
| 60 } | 60 } |
| 61 | 61 |
| 62 void add(List<int> data) { | 62 void add(List<int> data) { |
| 63 if (!_ignore) super.add(data); | 63 if (!_ignore) super.add(data); |
| 64 } | 64 } |
| 65 } | 65 } |
| 66 | 66 |
| 67 class _HttpInboundMessage extends Stream<List<int>> { | 67 class _HttpInboundMessage extends Stream<List<int>> { |
| 68 final _HttpIncoming _incoming; | 68 final _HttpIncoming _incoming; |
| 69 List<Cookie> _cookies; |
| 69 | 70 |
| 70 _HttpInboundMessage(_HttpIncoming this._incoming); | 71 _HttpInboundMessage(_HttpIncoming this._incoming); |
| 71 | 72 |
| 73 List<Cookie> get cookies { |
| 74 if (_cookies != null) return _cookies; |
| 75 return _cookies = headers._parseCookies(); |
| 76 } |
| 77 |
| 72 HttpHeaders get headers => _incoming.headers; | 78 HttpHeaders get headers => _incoming.headers; |
| 73 String get protocolVersion => headers.protocolVersion; | 79 String get protocolVersion => headers.protocolVersion; |
| 74 int get contentLength => headers.contentLength; | 80 int get contentLength => headers.contentLength; |
| 75 } | 81 } |
| 76 | 82 |
| 77 | 83 |
| 78 class _HttpRequest extends _HttpInboundMessage implements HttpRequest { | 84 class _HttpRequest extends _HttpInboundMessage implements HttpRequest { |
| 79 final HttpResponse response; | 85 final HttpResponse response; |
| 80 | 86 |
| 81 // Lazy initialized parsed query parameters. | 87 // Lazy initialized parsed query parameters. |
| 82 Map<String, String> _queryParameters; | 88 Map<String, String> _queryParameters; |
| 83 | 89 |
| 84 _HttpRequest(_HttpResponse this.response, _HttpIncoming _incoming) | 90 final _HttpServer _httpServer; |
| 91 |
| 92 HttpSession _session; |
| 93 |
| 94 _HttpRequest(_HttpResponse this.response, |
| 95 _HttpIncoming _incoming, |
| 96 _HttpServer this._httpServer) |
| 85 : super(_incoming) { | 97 : super(_incoming) { |
| 86 response.headers.persistentConnection = headers.persistentConnection; | 98 response.headers.persistentConnection = headers.persistentConnection; |
| 99 |
| 100 if (_httpServer._sessionManagerInstance != null) { |
| 101 // Map to session if exists. |
| 102 var sessionId = cookies.reduce(null, (last, cookie) { |
| 103 if (last != null) return last; |
| 104 return cookie.name.toUpperCase() == _DART_SESSION_ID ? |
| 105 cookie.value : null; |
| 106 }); |
| 107 if (sessionId != null) { |
| 108 _session = _httpServer._sessionManager.getSession(sessionId); |
| 109 if (_session != null) { |
| 110 _session._markSeen(); |
| 111 } |
| 112 } |
| 113 } |
| 87 } | 114 } |
| 88 | 115 |
| 89 StreamSubscription<T> listen(void onData(List<int> event), | 116 StreamSubscription<T> listen(void onData(List<int> event), |
| 90 {void onError(AsyncError error), | 117 {void onError(AsyncError error), |
| 91 void onDone(), | 118 void onDone(), |
| 92 bool unsubscribeOnError}) { | 119 bool unsubscribeOnError}) { |
| 93 return _incoming.listen(onData, | 120 return _incoming.listen(onData, |
| 94 onError: onError, | 121 onError: onError, |
| 95 onDone: onDone, | 122 onDone: onDone, |
| 96 unsubscribeOnError: unsubscribeOnError); | 123 unsubscribeOnError: unsubscribeOnError); |
| 97 } | 124 } |
| 98 | 125 |
| 99 Map<String, String> get queryParameters { | 126 Map<String, String> get queryParameters { |
| 100 if (_queryParameters == null) { | 127 if (_queryParameters == null) { |
| 101 _queryParameters = _HttpUtils.splitQueryString(uri.query); | 128 _queryParameters = _HttpUtils.splitQueryString(uri.query); |
| 102 } | 129 } |
| 103 return _queryParameters; | 130 return _queryParameters; |
| 104 } | 131 } |
| 105 | 132 |
| 106 Uri get uri => _incoming.uri; | 133 Uri get uri => _incoming.uri; |
| 107 | 134 |
| 108 String get method => _incoming.method; | 135 String get method => _incoming.method; |
| 136 |
| 137 HttpSession session([init(HttpSession session)]) { |
| 138 if (_session != null) { |
| 139 // It's already mapped, use it. |
| 140 return _session; |
| 141 } |
| 142 // Create session, store it in connection, and return. |
| 143 return _session = _httpServer._sessionManager.createSession(init); |
| 144 } |
| 109 } | 145 } |
| 110 | 146 |
| 111 | 147 |
| 112 class _HttpClientResponse | 148 class _HttpClientResponse |
| 113 extends _HttpInboundMessage implements HttpClientResponse { | 149 extends _HttpInboundMessage implements HttpClientResponse { |
| 114 List<RedirectInfo> get redirects => _httpRequest._responseRedirects; | 150 List<RedirectInfo> get redirects => _httpRequest._responseRedirects; |
| 115 | 151 |
| 116 // The HttpClient this response belongs to. | 152 // The HttpClient this response belongs to. |
| 117 final _HttpClient _httpClient; | 153 final _HttpClient _httpClient; |
| 118 | 154 |
| 119 // The HttpClientRequest of this response. | 155 // The HttpClientRequest of this response. |
| 120 final _HttpClientRequest _httpRequest; | 156 final _HttpClientRequest _httpRequest; |
| 121 | 157 |
| 158 List<Cookie> _cookies; |
| 159 |
| 122 _HttpClientResponse(_HttpIncoming _incoming, | 160 _HttpClientResponse(_HttpIncoming _incoming, |
| 123 _HttpClientRequest this._httpRequest, | 161 _HttpClientRequest this._httpRequest, |
| 124 _HttpClient this._httpClient) | 162 _HttpClient this._httpClient) |
| 125 : super(_incoming); | 163 : super(_incoming); |
| 126 | 164 |
| 127 int get statusCode => _incoming.statusCode; | 165 int get statusCode => _incoming.statusCode; |
| 128 String get reasonPhrase => _incoming.reasonPhrase; | 166 String get reasonPhrase => _incoming.reasonPhrase; |
| 129 | 167 |
| 168 List<Cookie> get cookies { |
| 169 if (_cookies != null) return _cookies; |
| 170 _cookies = new List<Cookie>(); |
| 171 List<String> values = headers["set-cookie"]; |
| 172 if (values != null) { |
| 173 values.forEach((value) { |
| 174 _cookies.add(new Cookie.fromSetCookieValue(value)); |
| 175 }); |
| 176 } |
| 177 return _cookies; |
| 178 } |
| 179 |
| 130 bool get isRedirect { | 180 bool get isRedirect { |
| 131 if (_httpRequest.method == "GET" || _httpRequest.method == "HEAD") { | 181 if (_httpRequest.method == "GET" || _httpRequest.method == "HEAD") { |
| 132 return statusCode == HttpStatus.MOVED_PERMANENTLY || | 182 return statusCode == HttpStatus.MOVED_PERMANENTLY || |
| 133 statusCode == HttpStatus.FOUND || | 183 statusCode == HttpStatus.FOUND || |
| 134 statusCode == HttpStatus.SEE_OTHER || | 184 statusCode == HttpStatus.SEE_OTHER || |
| 135 statusCode == HttpStatus.TEMPORARY_REDIRECT; | 185 statusCode == HttpStatus.TEMPORARY_REDIRECT; |
| 136 } else if (_httpRequest.method == "POST") { | 186 } else if (_httpRequest.method == "POST") { |
| 137 return statusCode == HttpStatus.SEE_OTHER; | 187 return statusCode == HttpStatus.SEE_OTHER; |
| 138 } | 188 } |
| 139 return false; | 189 return false; |
| (...skipping 169 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 309 final _HttpHeaders headers; | 359 final _HttpHeaders headers; |
| 310 | 360 |
| 311 final _HttpOutgoing _outgoing; | 361 final _HttpOutgoing _outgoing; |
| 312 bool _headersWritten = false; | 362 bool _headersWritten = false; |
| 313 bool _chunked = false; | 363 bool _chunked = false; |
| 314 } | 364 } |
| 315 | 365 |
| 316 | 366 |
| 317 class _HttpResponse extends _HttpOutboundMessage<HttpResponse> | 367 class _HttpResponse extends _HttpOutboundMessage<HttpResponse> |
| 318 implements HttpResponse { | 368 implements HttpResponse { |
| 319 _HttpResponse(String protocolVersion, _HttpOutgoing _outgoing) | 369 int statusCode = 200; |
| 370 String reasonPhrase = "OK"; |
| 371 |
| 372 List<Cookie> _cookies; |
| 373 _HttpRequest _httpRequest; |
| 374 |
| 375 _HttpResponse(String protocolVersion, |
| 376 _HttpOutgoing _outgoing) |
| 320 : super(protocolVersion, _outgoing); | 377 : super(protocolVersion, _outgoing); |
| 321 | 378 |
| 322 int statusCode = 200; | 379 List<Cookie> get cookies { |
| 323 | 380 if (_cookies == null) _cookies = new List<Cookie>(); |
| 324 String reasonPhrase = "OK"; | 381 return _cookies; |
| 382 } |
| 325 | 383 |
| 326 void _writeHeader() { | 384 void _writeHeader() { |
| 327 writeSP() => add([_CharCode.SP]); | 385 writeSP() => add([_CharCode.SP]); |
| 328 writeCRLF() => add([_CharCode.CR, _CharCode.LF]); | 386 writeCRLF() => add([_CharCode.CR, _CharCode.LF]); |
| 329 | 387 |
| 330 // Write status line. | 388 // Write status line. |
| 331 if (headers.protocolVersion == "1.1") { | 389 if (headers.protocolVersion == "1.1") { |
| 332 add(_Const.HTTP11); | 390 add(_Const.HTTP11); |
| 333 } else { | 391 } else { |
| 334 add(_Const.HTTP10); | 392 add(_Const.HTTP10); |
| 335 } | 393 } |
| 336 writeSP(); | 394 writeSP(); |
| 337 addString(statusCode.toString()); | 395 addString(statusCode.toString()); |
| 338 writeSP(); | 396 writeSP(); |
| 339 addString(reasonPhrase); | 397 addString(reasonPhrase); |
| 340 writeCRLF(); | 398 writeCRLF(); |
| 341 | 399 |
| 400 var session = _httpRequest._session; |
| 401 if (session != null && !session._destroyed) { |
| 402 // Make sure we only send the current session id. |
| 403 bool found = false; |
| 404 for (int i = 0; i < cookies.length; i++) { |
| 405 if (cookies[i].name.toUpperCase() == _DART_SESSION_ID) { |
| 406 cookies[i].value = session.id; |
| 407 cookies[i].httpOnly = true; |
| 408 found = true; |
| 409 break; |
| 410 } |
| 411 } |
| 412 if (!found) { |
| 413 cookies.add(new Cookie(_DART_SESSION_ID, session.id)..httpOnly = true); |
| 414 } |
| 415 } |
| 416 // Add all the cookies set to the headers. |
| 417 if (_cookies != null) { |
| 418 _cookies.forEach((cookie) { |
| 419 headers.add("set-cookie", cookie); |
| 420 }); |
| 421 } |
| 422 |
| 342 headers._finalize(); | 423 headers._finalize(); |
| 343 | 424 |
| 344 // Write headers. | 425 // Write headers. |
| 345 headers._write(this); | 426 headers._write(this); |
| 346 writeCRLF(); | 427 writeCRLF(); |
| 347 } | 428 } |
| 348 } | 429 } |
| 349 | 430 |
| 350 | 431 |
| 351 class _HttpClientRequest extends _HttpOutboundMessage<HttpClientRequest> | 432 class _HttpClientRequest extends _HttpOutboundMessage<HttpClientRequest> |
| (...skipping 491 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 843 void _removeCredentials(_Credentials cr) { | 924 void _removeCredentials(_Credentials cr) { |
| 844 int index = _credentials.indexOf(cr); | 925 int index = _credentials.indexOf(cr); |
| 845 if (index != -1) { | 926 if (index != -1) { |
| 846 _credentials.removeAt(index); | 927 _credentials.removeAt(index); |
| 847 } | 928 } |
| 848 } | 929 } |
| 849 } | 930 } |
| 850 | 931 |
| 851 | 932 |
| 852 class _HttpConnection { | 933 class _HttpConnection { |
| 853 _HttpConnection(Socket this._socket, Function this._handleRequest) { | 934 final Socket _socket; |
| 935 final _HttpServer _httpServer; |
| 936 |
| 937 _HttpConnection(Socket this._socket, _HttpServer this._httpServer) { |
| 854 var parser = new _HttpParser.requestParser(); | 938 var parser = new _HttpParser.requestParser(); |
| 855 _socket.pipe(parser); | 939 _socket.pipe(parser); |
| 856 parser.listen( | 940 parser.listen( |
| 857 (incoming) { | 941 (incoming) { |
| 858 var outgoing = new _HttpOutgoing(); | 942 var outgoing = new _HttpOutgoing(); |
| 859 outgoing.stream.then(_socket.writeStream); | 943 outgoing.stream.then(_socket.writeStream); |
| 860 var response = new _HttpResponse( | 944 var response = new _HttpResponse( |
| 861 incoming.headers.protocolVersion, | 945 incoming.headers.protocolVersion, |
| 862 outgoing); | 946 outgoing); |
| 863 var request = new _HttpRequest(response, incoming); | 947 var request = new _HttpRequest(response, incoming, _httpServer); |
| 948 response._httpRequest = request; |
| 864 outgoing.dataDone.then(() { | 949 outgoing.dataDone.then(() { |
| 865 if (response.headers.persistentConnection) { | 950 if (response.headers.persistentConnection) { |
| 866 // Mark incoming as done, preparing for next HTTP request. | 951 // Mark incoming as done, preparing for next HTTP request. |
| 867 incoming.done(); | 952 incoming.done(); |
| 868 } else { | 953 } else { |
| 869 // Close socket, keep-alive not used. | 954 // Close socket, keep-alive not used. |
| 870 _socket.destroy(); | 955 _socket.destroy(); |
| 871 } | 956 } |
| 872 }); | 957 }); |
| 873 _handleRequest(request); | 958 _httpServer._handleRequest(request); |
| 874 }, | 959 }, |
| 875 onDone: () { | 960 onDone: () { |
| 876 // TODO(ajohnsen): Remove connection from active connection queue. | 961 // TODO(ajohnsen): Remove connection from active connection queue. |
| 877 }, | 962 }, |
| 878 onError: (error) { | 963 onError: (error) { |
| 879 // TODO(ajohnsen): Handle errors. | 964 // TODO(ajohnsen): Handle errors. |
| 880 }); | 965 }); |
| 881 } | 966 } |
| 882 | |
| 883 final Function _handleRequest; | |
| 884 | |
| 885 final Socket _socket; | |
| 886 } | 967 } |
| 887 | 968 |
| 888 | 969 |
| 889 // HTTP server waiting for socket connections. | 970 // HTTP server waiting for socket connections. |
| 890 class _HttpServer extends Stream<HttpRequest> implements HttpServer { | 971 class _HttpServer extends Stream<HttpRequest> implements HttpServer { |
| 891 _HttpServer(String host, int port, int backlog) | 972 _HttpServer(String host, int port, int backlog) |
| 892 : _serverSocket = new ServerSocket(host, port, backlog), | 973 : _serverSocket = new ServerSocket(host, port, backlog), |
| 893 _closeServer = true; | 974 _closeServer = true; |
| 894 | 975 |
| 895 _HttpServer.listenOn(ServerSocket this._serverSocket) | 976 _HttpServer.listenOn(ServerSocket this._serverSocket) |
| 896 : _closeServer = false; | 977 : _closeServer = false; |
| 897 | 978 |
| 898 StreamSubscription<T> listen(void onData(T event), | 979 StreamSubscription<T> listen(void onData(T event), |
| 899 {void onError(AsyncError error), | 980 {void onError(AsyncError error), |
| 900 void onDone(), | 981 void onDone(), |
| 901 bool unsubscribeOnError}) { | 982 bool unsubscribeOnError}) { |
| 902 _serverSubscription = _serverSocket.listen((Socket socket) { | 983 _serverSubscription = _serverSocket.listen((Socket socket) { |
| 903 // Accept the client connection. | 984 // Accept the client connection. |
| 904 _HttpConnection connection = new _HttpConnection(socket, _handleRequest); | 985 _HttpConnection connection = new _HttpConnection(socket, this); |
| 905 _connections.add(connection); | 986 _connections.add(connection); |
| 906 // TODO(ajohnsen): Listen to closed sockets. | 987 // TODO(ajohnsen): Listen to closed sockets. |
| 907 }); | 988 }); |
| 908 return _controller.listen(onData, | 989 return _controller.listen(onData, |
| 909 onError: onError, | 990 onError: onError, |
| 910 onDone: onDone, | 991 onDone: onDone, |
| 911 unsubscribeOnError: unsubscribeOnError); | 992 unsubscribeOnError: unsubscribeOnError); |
| 912 } | 993 } |
| 913 | 994 |
| 914 void close() { | 995 void close() { |
| (...skipping 247 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1162 | 1243 |
| 1163 | 1244 |
| 1164 class _RedirectInfo implements RedirectInfo { | 1245 class _RedirectInfo implements RedirectInfo { |
| 1165 const _RedirectInfo(int this.statusCode, | 1246 const _RedirectInfo(int this.statusCode, |
| 1166 String this.method, | 1247 String this.method, |
| 1167 Uri this.location); | 1248 Uri this.location); |
| 1168 final int statusCode; | 1249 final int statusCode; |
| 1169 final String method; | 1250 final String method; |
| 1170 final Uri location; | 1251 final Uri location; |
| 1171 } | 1252 } |
| OLD | NEW |