[dart] r16858 committed - Re-implement http sessions....

32 views
Skip to first unread message

da...@googlecode.com

unread,
Jan 9, 2013, 10:32:00 AM1/9/13
to com...@dartlang.org
Revision: 16858
Author: ajoh...@google.com
Date: Wed Jan 9 07:31:38 2013
Log: Re-implement http sessions.

BUG=

Review URL: https://codereview.chromium.org//11829025
http://code.google.com/p/dart/source/detail?r=16858

Modified:
/experimental/lib_v2_io/dart/sdk/lib/io/http_headers.dart
/experimental/lib_v2_io/dart/sdk/lib/io/http_impl.dart
/experimental/lib_v2_io/dart/tests/standalone/io/http_session_test.dart
/experimental/lib_v2_io/dart/tests/standalone/standalone.status

=======================================
--- /experimental/lib_v2_io/dart/sdk/lib/io/http_headers.dart Tue Jan 8
02:35:10 2013
+++ /experimental/lib_v2_io/dart/sdk/lib/io/http_headers.dart Wed Jan 9
07:31:38 2013
@@ -405,6 +405,71 @@
return sb.toString();
}

+ List<Cookie> _parseCookies() {
+ // Parse a Cookie header value according to the rules in RFC 6265.
+ var cookies = new List<Cookie>();
+ void parseCookieString(String s) {
+ int index = 0;
+
+ bool done() => index == s.length;
+
+ void skipWS() {
+ while (!done()) {
+ if (s[index] != " " && s[index] != "\t") return;
+ index++;
+ }
+ }
+
+ String parseName() {
+ int start = index;
+ while (!done()) {
+ if (s[index] == " " || s[index] == "\t" || s[index] == "=")
break;
+ index++;
+ }
+ return s.substring(start, index).toLowerCase();
+ }
+
+ String parseValue() {
+ int start = index;
+ while (!done()) {
+ if (s[index] == " " || s[index] == "\t" || s[index] == ";")
break;
+ index++;
+ }
+ return s.substring(start, index).toLowerCase();
+ }
+
+ void expect(String expected) {
+ if (done()) {
+ throw new HttpException("Failed to parse header value [$s]");
+ }
+ if (s[index] != expected) {
+ throw new HttpException("Failed to parse header value [$s]");
+ }
+ index++;
+ }
+
+ while (!done()) {
+ skipWS();
+ if (done()) return;
+ String name = parseName();
+ skipWS();
+ expect("=");
+ skipWS();
+ String value = parseValue();
+ cookies.add(new _Cookie(name, value));
+ skipWS();
+ if (done()) return;
+ expect(";");
+ }
+ }
+ List<String> values = this["cookie"];
+ if (values != null) {
+ values.forEach((headerValue) => parseCookieString(headerValue));
+ }
+ return cookies;
+ }
+
+
bool _mutable = true; // Are the headers currently mutable?
Map<String, List<String>> _headers;
List<String> _noFoldingHeaders;
=======================================
--- /experimental/lib_v2_io/dart/sdk/lib/io/http_impl.dart Wed Jan 9
07:29:32 2013
+++ /experimental/lib_v2_io/dart/sdk/lib/io/http_impl.dart Wed Jan 9
07:31:38 2013
@@ -66,9 +66,15 @@

class _HttpInboundMessage extends Stream<List<int>> {
final _HttpIncoming _incoming;
+ List<Cookie> _cookies;

_HttpInboundMessage(_HttpIncoming this._incoming);

+ List<Cookie> get cookies {
+ if (_cookies != null) return _cookies;
+ return _cookies = headers._parseCookies();
+ }
+
HttpHeaders get headers => _incoming.headers;
String get protocolVersion => headers.protocolVersion;
int get contentLength => headers.contentLength;
@@ -81,9 +87,30 @@
// Lazy initialized parsed query parameters.
Map<String, String> _queryParameters;

- _HttpRequest(_HttpResponse this.response, _HttpIncoming _incoming)
+ final _HttpServer _httpServer;
+
+ HttpSession _session;
+
+ _HttpRequest(_HttpResponse this.response,
+ _HttpIncoming _incoming,
+ _HttpServer this._httpServer)
: super(_incoming) {
response.headers.persistentConnection = headers.persistentConnection;
+
+ if (_httpServer._sessionManagerInstance != null) {
+ // Map to session if exists.
+ var sessionId = cookies.reduce(null, (last, cookie) {
+ if (last != null) return last;
+ return cookie.name.toUpperCase() == _DART_SESSION_ID ?
+ cookie.value : null;
+ });
+ if (sessionId != null) {
+ _session = _httpServer._sessionManager.getSession(sessionId);
+ if (_session != null) {
+ _session._markSeen();
+ }
+ }
+ }
}

StreamSubscription<T> listen(void onData(List<int> event),
@@ -106,6 +133,15 @@
Uri get uri => _incoming.uri;

String get method => _incoming.method;
+
+ HttpSession session([init(HttpSession session)]) {
+ if (_session != null) {
+ // It's already mapped, use it.
+ return _session;
+ }
+ // Create session, store it in connection, and return.
+ return _session = _httpServer._sessionManager.createSession(init);
+ }
}


@@ -119,6 +155,8 @@
// The HttpClientRequest of this response.
final _HttpClientRequest _httpRequest;

+ List<Cookie> _cookies;
+
_HttpClientResponse(_HttpIncoming _incoming,
_HttpClientRequest this._httpRequest,
_HttpClient this._httpClient)
@@ -127,6 +165,18 @@
int get statusCode => _incoming.statusCode;
String get reasonPhrase => _incoming.reasonPhrase;

+ List<Cookie> get cookies {
+ if (_cookies != null) return _cookies;
+ _cookies = new List<Cookie>();
+ List<String> values = headers["set-cookie"];
+ if (values != null) {
+ values.forEach((value) {
+ _cookies.add(new Cookie.fromSetCookieValue(value));
+ });
+ }
+ return _cookies;
+ }
+
bool get isRedirect {
if (_httpRequest.method == "GET" || _httpRequest.method == "HEAD") {
return statusCode == HttpStatus.MOVED_PERMANENTLY ||
@@ -316,12 +366,20 @@

class _HttpResponse extends _HttpOutboundMessage<HttpResponse>
implements HttpResponse {
- _HttpResponse(String protocolVersion, _HttpOutgoing _outgoing)
+ int statusCode = 200;
+ String reasonPhrase = "OK";
+
+ List<Cookie> _cookies;
+ _HttpRequest _httpRequest;
+
+ _HttpResponse(String protocolVersion,
+ _HttpOutgoing _outgoing)
: super(protocolVersion, _outgoing);

- int statusCode = 200;
-
- String reasonPhrase = "OK";
+ List<Cookie> get cookies {
+ if (_cookies == null) _cookies = new List<Cookie>();
+ return _cookies;
+ }

void _writeHeader() {
writeSP() => add([_CharCode.SP]);
@@ -338,6 +396,29 @@
writeSP();
addString(reasonPhrase);
writeCRLF();
+
+ var session = _httpRequest._session;
+ if (session != null && !session._destroyed) {
+ // Make sure we only send the current session id.
+ bool found = false;
+ for (int i = 0; i < cookies.length; i++) {
+ if (cookies[i].name.toUpperCase() == _DART_SESSION_ID) {
+ cookies[i].value = session.id;
+ cookies[i].httpOnly = true;
+ found = true;
+ break;
+ }
+ }
+ if (!found) {
+ cookies.add(new Cookie(_DART_SESSION_ID, session.id)..httpOnly =
true);
+ }
+ }
+ // Add all the cookies set to the headers.
+ if (_cookies != null) {
+ _cookies.forEach((cookie) {
+ headers.add("set-cookie", cookie);
+ });
+ }

headers._finalize();

@@ -850,7 +931,10 @@


class _HttpConnection {
- _HttpConnection(Socket this._socket, Function this._handleRequest) {
+ final Socket _socket;
+ final _HttpServer _httpServer;
+
+ _HttpConnection(Socket this._socket, _HttpServer this._httpServer) {
var parser = new _HttpParser.requestParser();
_socket.pipe(parser);
parser.listen(
@@ -860,7 +944,8 @@
var response = new _HttpResponse(
incoming.headers.protocolVersion,
outgoing);
- var request = new _HttpRequest(response, incoming);
+ var request = new _HttpRequest(response, incoming, _httpServer);
+ response._httpRequest = request;
outgoing.dataDone.then(() {
if (response.headers.persistentConnection) {
// Mark incoming as done, preparing for next HTTP request.
@@ -870,7 +955,7 @@
_socket.destroy();
}
});
- _handleRequest(request);
+ _httpServer._handleRequest(request);
},
onDone: () {
// TODO(ajohnsen): Remove connection from active connection
queue.
@@ -879,10 +964,6 @@
// TODO(ajohnsen): Handle errors.
});
}
-
- final Function _handleRequest;
-
- final Socket _socket;
}


@@ -901,7 +982,7 @@
bool unsubscribeOnError}) {
_serverSubscription = _serverSocket.listen((Socket socket) {
// Accept the client connection.
- _HttpConnection connection = new _HttpConnection(socket,
_handleRequest);
+ _HttpConnection connection = new _HttpConnection(socket, this);
_connections.add(connection);
// TODO(ajohnsen): Listen to closed sockets.
});
=======================================
--- /experimental/lib_v2_io/dart/tests/standalone/io/http_session_test.dart
Mon Jan 7 03:23:16 2013
+++ /experimental/lib_v2_io/dart/tests/standalone/io/http_session_test.dart
Wed Jan 9 07:31:38 2013
@@ -21,33 +21,26 @@
}

Future<String> connectGetSession(int port, [String session]) {
- var c = new Completer();
var client = new HttpClient();
- var conn = client.get("127.0.0.1", port, "/");
- conn.onRequest = (request) {
- if (session != null) {
- request.cookies.add(new Cookie(SESSION_ID, session));
- }
- request.outputStream.close();
- };
- conn.onResponse = (response) {
- response.inputStream.onData = response.inputStream.read;
- response.inputStream.onClosed = () {
- client.shutdown();
- c.complete(getSessionId(response.cookies));
- };
- };
- return c.future;
+ return client.get("127.0.0.1", port, "/")
+ .then((request) {
+ if (session != null) {
+ request.cookies.add(new Cookie(SESSION_ID, session));
+ }
+ return request.close();
+ })
+ .then((response) {
+ return response.reduce(getSessionId(response.cookies), (v, _) => v);
+ });
}

void testSessions(int sessionCount) {
- HttpServer server = new HttpServer();
- server.listen("127.0.0.1", 0);
+ HttpServer server = new HttpServer("127.0.0.1", 0);
var sessions = new Set();
- server.defaultRequestHandler = (request, response) {
+ server.listen((request) {
sessions.add(request.session().id);
- response.outputStream.close();
- };
+ request.response.close();
+ });

var futures = [];
for (int i = 0; i < sessionCount; i++) {
@@ -69,18 +62,17 @@
}

void testTimeout(int sessionCount) {
- HttpServer server = new HttpServer();
+ HttpServer server = new HttpServer("127.0.0.1", 0);
server.sessionTimeout = 0;
- server.listen("127.0.0.1", 0);
var timeouts = [];
- server.defaultRequestHandler = (request, response) {
+ server.listen((request) {
var c = new Completer();
timeouts.add(c.future);
request.session().onTimeout = () {
c.complete(null);
};
- response.outputStream.close();
- };
+ request.response.close();
+ });

var futures = [];
for (int i = 0; i < sessionCount; i++) {
=======================================
--- /experimental/lib_v2_io/dart/tests/standalone/standalone.status Wed
Jan 9 07:29:32 2013
+++ /experimental/lib_v2_io/dart/tests/standalone/standalone.status Wed
Jan 9 07:31:38 2013
@@ -20,7 +20,6 @@
io/http_server_early_server_close_test: fail
io/http_server_handler_test: fail
io/http_server_socket_test: fail
-io/http_session_test: fail
io/http_shutdown_test: fail
io/https_client_certificate_test: fail
io/https_client_test: fail
Reply all
Reply to author
Forward
0 new messages