4
4

More than 5 years have passed since last update.

nghttp2をmac osx でビルドしたい

Last updated at Posted at 2014-11-03

http2confにいるんだが、nghttp2くらいはbuildしてくるべきだった、とかつぶやいたら色々とソリューションを教えてもらった。

自動化させたら世界一の @deeeet さんからDockerfileとかももらったんだけど、Dockerよりももうちょっと手軽にお願いしたかった。nghttp2がmacでビルドできればベスト。

色々試したけど、最終的に夏風さんに頼んでbrewでinstallできるようにしてもらった。

install nghttp2 by brew

$ curl -o /usr/local/Library/Formula/nghttp2.rb https://gist.githubusercontent.com/summerwind/6295114/raw/nghttp2.rb

$ brew install nghttp2
$ nghttpd --no-tls -v 8888

こうしておいて、後は夏風さんのclientを実装する。途中までclient頑張って書いてたけど、途中からずるしてコピペした。

client.js

var net = require('net'),
    hpack = require('./hpack');

var FRAME_HEADER_LEN = 9;

function createSettingsFrame(ack) {
  var flag = ack ? 0x1 : 0x0;

  var frameHeader = new Buffer(FRAME_HEADER_LEN);
  frameHeader.writeUInt32BE(0x0, 0);
  frameHeader.writeUInt8(0x4, 3);
  frameHeader.writeUInt8(flag, 4);
  frameHeader.writeUInt32BE(0x0, 5);

  return frameHeader;
}

function encodeHeaders(headers) {
  var headerBlocks = [];

  headers.forEach(function(header){
    var prefix = new Buffer(1);
    prefix.fill(0);
    headerBlocks.push(prefix);

    var name = hpack.encodeString(header[0]);
    headerBlocks.push(name);

    var value = hpack.encodeString(header[1]);
    headerBlocks.push(value);
  });

  return Buffer.concat(headerBlocks);
}

function createHeadersFrame(headers) {
  var headerBlocks = encodeHeaders(headers);

  var frameHeader = new Buffer(FRAME_HEADER_LEN);
  frameHeader.writeUInt32BE(headerBlocks.length << 8, 0);
  frameHeader.writeUInt8(0x1, 3);
  frameHeader.writeUInt8(0x5, 4);
  frameHeader.writeUInt32BE(0x1, 5);

  return Buffer.concat([frameHeader, headerBlocks]);
};

function debug(msg) {
  console.log('[debug]', msg);
}


var conn = net.connect(8888, '127.0.0.1');
var frameBuffer = new Buffer(0);
var bodyBuffer = [];

conn.on('connect', function(){
  conn.write('PRI * HTTP/2.0\r\n\r\nSM\r\n\r\n', 'utf8');
  conn.write(createSettingsFrame(false));
  debug('Send SETTINGS frame');
});

conn.on('data', function(chunk){
  frameBuffer = Buffer.concat([frameBuffer, chunk]);

  while (frameBuffer.length >= FRAME_HEADER_LEN) {
    var length = FRAME_HEADER_LEN;
        length += frameBuffer.readUInt32BE(0) >> 8;
    if (frameBuffer.length < length) {
      return;
    }

    var frame = frameBuffer.slice(0, length);
    frameBuffer = frameBuffer.slice(length);

    if (frame[3] === 0x4 && frame[4] === 0x0) {
      conn.write(createSettingsFrame(true));
      debug('Send SETTINGS frame with ACK flag');
      continue;
    }

    if (frame[3] === 0x4 && frame[4] === 0x1) {
      var headers = [
        [ ':method', 'GET' ],
        [ ':path', '/' ],
        [ ':scheme', 'http' ],
        [ ':authority', 'localhost:8888' ]
      ];

      conn.write(createHeadersFrame(headers));
      debug('Send HEADERS frame');
      continue;
    }

    if (frame[3] === 0x0 && frame[4] === 0x0) {
      bodyBuffer.push(frame.slice(FRAME_HEADER_LEN));
    }

    if (frame[3] === 0x0 && frame[4] === 0x1) {
      var body = Buffer.concat(bodyBuffer);
      console.log(body.toString());
      conn.end();
    }
  }
});

hpack.js

function encodeInteger(num, prefix) {
  var limit = Math.pow(2, prefix) - 1;

  if (num < limit) {
    return new Buffer([num]);
  }

  var octets = [limit];
  num -= limit;
  while (num >= 128) {
    octets.push(num % 128 | 0x80);
    num >>= 7;
  }
  octets.push(num);

  return new Buffer(octets);
}

function encodeString(str) {
  var buffers = [];
  var value = new Buffer(str, 'ascii');

  buffers.push(encodeInteger(value.length, 7));
  buffers.push(value);

  return Buffer.concat(buffers);
}

exports.encodeInteger = encodeInteger;
exports.encodeString = encodeString;

こんな感じで動く。

$ node client.js
<html><head><title>404</title></head><body><h1>404</h1><hr><address>nghttpd nghttp2/0.6.4 at port 8888</address></body></html><html><head><title>404</title></head><body><h1>404</h1><hr><address>nghttpd nghttp2/0.6.4 at port 8888</address></body></html>

こんなのが返ってくればOK

4
4
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
4
4