Tuesday, April 24, 2012

Bad SPDY/3 Headers

‹prev | My Chain | next›

Up tonight, I continue in my effort to get node-spdy working with SPDY version 3. I have Chrome speaking SPDY v3 by virtue of about:flags settings. I have begun SPDY v3 implementation in the node-spdy server by copying the v2 implementation to v3, updating the compression dictionary, and making a change or two to the header parsing.

As of last night, I am able to parse headers from the incoming session, but that is about it. No response is ever sent and I can see no evidence that the request listener ever sees the request.

The headers look like:
headers: 
   { ':host': 'localhost:3000',
     ':method': 'GET',
     ':path': '/',
     ':scheme': 'https',
     ':version': 'HTTP/1.1',
     accept: 'text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8',
     'accept-charset': 'ISO-8859-1,utf-8;q=0.7,*;q=0.3',
     'accept-encoding': 'gzip,deflate,sdch',
     'accept-language': 'en-US,en;q=0.8',
     'cache-control': 'no-cache',
     pragma: 'no-cache',
     'user-agent': 'Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/536.8 (KHTML, like Gecko) Chrome/20.0.1105.0 Safari/536.8' } }
Now that I think about it, I have no idea why some of those headers begin with a colon (e.g. ':host'). That seems like it must be coming from Chrome. If it were a zlib inflation error, the values would have additional characters as well. Besides, a bit or two offset would cause the whole thing to crash.

The spdy/2 version of the headers definitely does not include the prepended colon:
headers:
   { accept: 'text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8',
     'accept-charset': 'ISO-8859-1,utf-8;q=0.7,*;q=0.3',
     'accept-encoding': 'gzip,deflate,sdch',
     'accept-language': 'en-US,en;q=0.8',
     'cache-control': 'no-cache',
     host: 'localhost:3000',
     method: 'GET',
     pragma: 'no-cache',
     scheme: 'https',
     url: '/',
     'user-agent': 'Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/536.8 (KHTML, like Gecko) Chrome/20.0.1105.0 Safari/536.8',
     version: 'HTTP/1.1' }
So, I manually remove the colons from the header names in spdy/3:
protocol.parseHeaders = function parseHeaders(pairs) {
  // ...
  while(count > 0) {
    var k = readString(),
        v = readString();

    k = k.replace(/:/, '');
    headers[k] = v;

    count--;
  }

  return headers;
};
That gives me better headers:
headers:
   { host: 'localhost:3000',
     method: 'GET',
     path: '/',
     scheme: 'https',
     version: 'HTTP/1.1',
     accept: 'text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8',
     'accept-charset': 'ISO-8859-1,utf-8;q=0.7,*;q=0.3',
     'accept-encoding': 'gzip,deflate,sdch',
     'accept-language': 'en-US,en;q=0.8',
     'cache-control': 'no-cache',
     pragma: 'no-cache',
     'user-agent': 'Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/536.8 (KHTML, like Gecko) Chrome/20.0.1105.0 Safari/536.8' } 
But still no response or even an attempt at a response.

Hrm... the spdy/3 SYN_STREAM does not have a url—could that be it?
protocol.parseHeaders = function parseHeaders(pairs) {
  // ...
  while(count > 0) {
    var k = readString(),
        v = readString();

    k = k.replace(/:/, '');
    headers[k] = v;

    if (k == 'path') {
      headers['url'] = v;
    }

    count--;
  }

  return headers;
};
As expected, that does produce a url request header:
headers: 
   { host: 'localhost:3000',
     method: 'GET',
     path: '/',
     url: '/',
     scheme: 'https',
     version: 'HTTP/1.1',
     // ...
   }
But, more importantly, I finally move past my block. The response is now being sent back to the browser:
writeHead
replyFrame
writeHead
write
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"><html><head><title>Express</title><link rel="stylesheet" href="/stylesheets/style.css"/><script src="/main.js"></script></head><body><h1>Express</h1><p>Welcome to Express</p></body></html>
...
Unfortunately, this does not quite work as a server error still arises. But at least it is a different error this time. Tantalizingly close, I have to call it a night.

Update: The colon headers are, of course, part of the spec. Folding them back into a new url header is necessary, but removing the colons was not. It seems that the response also needs colon headers—hopefully that accounts for most of my remaining problems.

Day #366

No comments:

Post a Comment