Skip to content


Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP


Static Range Request Creating Multiple Sessions and Clobbering Cookie #394

seanabrahams opened this Issue · 15 comments

5 participants


I have a GET that stores some data to a session (req.session.token = token) and responds with a page that loads a video (809k) using HTML5's video tag.

The video is served up via static middleware as a range request (status code 206). Interestingly, it appears on each chunk Connect seems to be creating a new session in Redis and clobbering the original cookie in the user's browser.

Since the user's cookie is clobbered with the most recent session key created we no longer have access to the original session data.


node 0.4.12
├── connect-redis@1.1.0 
├─┬ express@2.4.3 
│ ├── connect@1.7.1 
│ ├── mime@1.2.4 
│ └── qs@0.3.1 
├─┬ jade@0.16.2 
│ ├── commander@0.1.0 
│ └── mkdirp@0.0.7 
└── redis@0.6.7


 * Module dependencies.

var express = require('express'),
  redis = require("redis"),
  RedisStore = require('connect-redis')(express);

var app = module.exports = express.createServer();

// Configuration

  app.set('views', __dirname + '/views');
  app.set('view engine', 'jade');
  app.use(express.session({ secret: "alkjaslkfjslkdfjdf", store: new RedisStore(),  key: 'express.sid' }));
  app.use(express.static(__dirname + '/public'));

app.configure('development', function(){
  app.use(express.errorHandler({ dumpExceptions: true, showStack: true })); 

app.configure('production', function(){

// Routes

app.get('/', function(req, res){
  req.session.token = 'Hello Token';
  res.render('index', {
    title: 'Express'

console.log("Express server listening on port %d in %s mode", app.address().port, app.settings.env);


h1= title
p Welcome to #{title}
video(src="/videos/3.mp4", autoplay="yes", loop="loop", preload="auto", poster="/videos/3.jpg")

HTML output

<!DOCTYPE html>
    <link rel="stylesheet" href="/stylesheets/style.css"/>
    <p>Welcome to Express</p>
    <video src="/videos/3.mp4" autoplay="yes" loop="loop" preload="auto" poster="/videos/3.jpg">
      <source src="/videos/3.mp4"></source>

KEYS * in Redis before request:

redis> keys *
(empty list or set)

KEYS * in Redis after 1 request:

redis> keys *
1) "sess:1at93LcqrZiFAbJDj4Xdgjvk.VxUwdqRxeQDepllW763Q5xzdwWgPiXV3h7W+ktlyLJs"
2) "sess:cbf0k5BjIXgMrNoQWGaPLg2z.HdQxyfsBNAwLKcsirMxlNAGhQGQbGslBAhZB+i3c0vw"
3) "sess:rJHmen3u910vUC5L7HculveC.l++B9kqO35sEUQp79+rKaGl4nLAoNECmnE5TtQ8Ua/I"
tj commented

this is probably a two-part problem. a) we Set-Cookie always right now, which really needs to be changed (I have an issue open), b) perhaps the browser is not sending the cookie for these requests, causing connect to generate a new one. I'll see if I can reproduce this

tj commented

awesome thanks, appreciate it

tj commented

seems fine to me, I tried your repo and my own. though there is a chance that the res.end() saving the session may not have fired before assets start loading, clobbering the sess


Looks like it may be specific to Safari...


Ran into the same Safari-specific issue. It appears to be fixed on 2.5.7.


I retract what I just said, it does not. Testing with Express 2.5.7 and Connect 1.8.5. Only mp4 files, only on Safari cause this issue. part[0] of the cookie string != hash(part[1])... will report back if I can find it.

@seanabrahams did you find a fix?


@frank06 Unfortunately I did not. We switched directions and this became a non-issue for us.


Ok found it (applies at least to Safari 5.0.3)

It's the default fingerprint function in Connect that makes the comparison fail and therefore triggers new session creation upon mp4 requests from Safari.

This is because mp4 requests do not send the real user agent, and the default fingerprint relies on it.

For any standard request, Safari will send something like: Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10_6_4; en-us) AppleWebKit/533.19.4 (KHTML, like Gecko) Version/5.0.3 Safari/533.19.4

For mp4 files, it will send: Apple Mac OS X v10.6.4 CoreMedia v1.0.0.10F569.

@visionmedia You may want to either change the default fingerprint function (at the moment I don't know to what, really) or put a big notice that it will make mp4 requests fail.



tj commented

@frank06 I've removed it actually, it was causing too many issues (chrome frame etc), I might not have removed it for 1.x though


It took me a long time to debug my way here but I'm pretty sure I've hit the same issue with just using static .wav and .mp3's in Safari 5.1.3 (works fine in Chrome 18.0.1025.45 beta).

That is: executing new Audio('/sound/hello.wav'); in the client gets you a new session id.

The reason seems to be that Safari hits the .wav twice. First using the regular user-agent string:

"Mozilla/5.0 (Macintosh; Intel Mac OS X 1073) AppleWebKit/534.53.11 (KHTML, like Gecko) Version/5.1.3 Safari/534.53.10"

and the second time (through a plugin?) with another user-agent string:

"AppleCoreMedia/ (Macintosh; U; Intel Mac OS X 1073; en_us)"

As I'm using express 2.5.8 which depends on 1.8.5, I resorted to the following workaround:

  fingerprint: function (req) {
    return "hello";

Same here, express 2.5.8 but on Opera 11.61 is creating an additional, seemingly unused, session keys in Redis. The opera cookie seems to remain the same. Debugging the code shows that the cookie sent by the browser is the same as what opera shows. My static middleware checks for css and javascript requests first then goes on to the custom logic, afterwards the extra session is created. The fingerprint workaround doesn't seem to work for me.


It was the favicon. Apparently opera doesn't send cookie headers for those. So far I'm working around this by placing this middleware function right after my static server (which serves the favicon also). I wonder if this could be done more elegant...

app.use ( function ( req, rs, next ) {
    if ( req.url.indexOf('favicon.ico') == -1 ) {
        next ()
    } else {
} )
tj commented

1.8.6 has the fingerprint defaulted to '', and it's removed all together in 2.x

@tj tj closed this
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Something went wrong with that request. Please try again.