transport-http.js 3.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103
  1. "use strict";
  2. var makeChannel = require('culvert');
  3. var bodec = require('bodec');
  4. var pktLine = require('../lib/pkt-line');
  5. var wrapHandler = require('../lib/wrap-handler');
  6. module.exports = function (request) {
  7. return function httpTransport(gitUrl, username, password) {
  8. // Send Auth header if username is set
  9. var auth;
  10. if (username) {
  11. auth = "Basic " + btoa(username + ":" + (password || ""));
  12. }
  13. return function (serviceName, onError) {
  14. // Wrap our handler functions to route errors properly.
  15. onResponse = wrapHandler(onResponse, onError);
  16. onWrite = wrapHandler(onWrite, onError);
  17. onResult = wrapHandler(onResult, onError);
  18. // Create a duplex channel with transform for internal use.
  19. var serverChannel = makeChannel();//0, "server");
  20. var clientChannel = makeChannel();//0, "client");
  21. var socket = {
  22. put: serverChannel.put,
  23. drain: serverChannel.drain,
  24. take: clientChannel.take
  25. };
  26. // Send the initial request to start the connection.
  27. var headers = {};
  28. if (auth) headers.Authorization = auth;
  29. request("GET", gitUrl + "/info/refs?service=" + serviceName, headers, onResponse);
  30. // Prep for later requests
  31. var bodyParts = [];
  32. var bodyWrite = pktLine.framer(function (chunk) {
  33. bodyParts.push(chunk);
  34. });
  35. headers["Content-Type"] = "application/x-" + serviceName + "-request";
  36. socket.take(onWrite);
  37. var verified = 0;
  38. var parseResponse = pktLine.deframer(function (line) {
  39. if (verified === 2) {
  40. socket.put(line);
  41. }
  42. else if (verified === 0) {
  43. if (line !== "# service=" + serviceName) {
  44. throw new Error("Illegal service response");
  45. }
  46. verified = 1;
  47. }
  48. else if (verified === 1) {
  49. if (line !== null) {
  50. throw new Error("Expected null after service name");
  51. }
  52. verified = 2;
  53. }
  54. });
  55. // Return the other half of the duplex channel for the protocol logic to use.
  56. return {
  57. put: clientChannel.put,
  58. drain: clientChannel.drain,
  59. take: serverChannel.take
  60. };
  61. function onResponse(res) {
  62. if (res.statusCode !== 200) {
  63. throw new Error("Invalid response: " + res.statusCode);
  64. }
  65. if (res.headers["content-type"] !== "application/x-" + serviceName + "-advertisement") {
  66. throw new Error("Not a smart http git server");
  67. }
  68. parseResponse(res.body);
  69. }
  70. function onWrite(item) {
  71. if (item === undefined) return socket.put();
  72. bodyWrite(item);
  73. socket.take(onWrite);
  74. if (item !== "done\n" || !bodyParts.length) return;
  75. var body = bodec.join(bodyParts);
  76. bodyParts.length = 0;
  77. request("POST", gitUrl + "/" + serviceName, headers, body, onResult);
  78. }
  79. function onResult(res) {
  80. if (res.statusCode !== 200) {
  81. throw new Error("Invalid result: " + res.statusCode);
  82. }
  83. if (res.headers["content-type"] !== "application/x-" + serviceName + "-result") {
  84. throw new Error("Not a smart http git server");
  85. }
  86. parseResponse(res.body);
  87. }
  88. };
  89. };
  90. };