Proxy requests.

This commit is contained in:
Julien Fontanet
2014-09-23 17:30:19 +02:00
parent 05b1bffeef
commit acb2ede658
3 changed files with 137 additions and 31 deletions

View File

@@ -1,5 +1,3 @@
{stringify: $formatQueryString} = require 'querystring'
$findWhere = require 'lodash.find'
$forEach = require 'lodash.foreach'
$isArray = require 'lodash.isarray'
@@ -691,7 +689,6 @@ exports.revert.params = {
id: { type: 'string' }
}
# export a VM
exports.export = ({id, compress}) ->
compress ?= true
try
@@ -700,7 +697,7 @@ exports.export = ({id, compress}) ->
@throw 'NO_SUCH_OBJECT'
host = @getObject VM.$container
do (type = host.type) ->
do (type = host.type) =>
if type is 'pool'
host = @getObject host.master, 'host'
else unless type is 'host'
@@ -708,43 +705,48 @@ exports.export = ({id, compress}) ->
{sessionId} = @getXAPI host
return @registerProxyRequest {
url = $wait @registerProxyRequest {
method: 'get'
hostname: host.address
path: '/export/?' + $formatQueryString {
pathname: '/export/'
query: {
session_id: sessionId
ref: VM.ref
use_compression: if compress then 'true' else false
}
}
return {
$getFrom: url
}
exports.export.permission = 'admin'
exports.export.params = {
id: { type: 'string' }
compress: { type: 'boolean', optional: true }
}
# import a VM
exports.import = ({id, file}) ->
# FIXME
exports.import = ({host}) ->
try
VM = @getObject id, 'VM'
host = @getObject host, 'host'
catch
@throw 'NO_SUCH_OBJECT'
host = @getObject VM.$container
do (type = host.type) ->
if type is 'pool'
host = @getObject host.master, 'host'
else unless type is 'host'
throw new Error "unexpected type: got #{type} instead of host"
{sessionId} = @getXAPI host
return @registerProxyRequest {
url = $wait @registerProxyRequest {
method: 'post'
hostname: host.address
path: '/import/' + $formatQueryString session_id: sessionId
pathname: '/import/'
query: {
session_id: sessionId
}
}
return {
$sendTo: url
}
exports.import.permission = 'admin'
exports.import.params = {
id: { type: 'string' }
host: { type: 'string' }
}

100
src/proxy-request.js Normal file
View File

@@ -0,0 +1,100 @@
'use strict';
//====================================================================
var formatQueryString = require('querystring').stringify;
var httpRequest = require('http').request;
var httpsRequest = require('https').request;
var parseUrl = require('url').parse;
var assign = require('lodash.assign');
var debug = require('debug')('xo:proxyRequest');
var forEach = require('lodash.foreach');
var isString = require('lodash.isstring');
//====================================================================
var DEFAULTS = {
method: 'GET',
};
var HTTP_RE = /^http(s?):?$/;
//====================================================================
function proxyRequest(opts, upReq, upRes) {
if (isString(opts)) {
debug('parsing URL %s', opts);
opts = parseUrl(opts);
}
// Merges options with defaults.
opts = assign({}, DEFAULTS, opts);
opts.headers = assign({},
DEFAULTS.headers,
upReq.headers,
{
connection: 'close',
host: opts.hostname || opts.host,
},
opts.headers
);
// `http(s).request()` does not understand pathname, query and
// search.
if (!opts.path) {
var path = opts.pathname || '/';
var query;
if (opts.search) {
path += opts.search;
} else if ((query = opts.query)) {
if (!isString(query)) {
query = formatQueryString(query);
}
path += '?' + query;
}
opts.path = path;
}
var matches;
var isSecure = !!(
opts.protocol &&
(matches = opts.protocol.match(HTTP_RE)) &&
matches[1]
);
delete opts.protocol;
debug('proxying HTTP%s request', isSecure ? 's' : '');
var request = isSecure ? httpsRequest : httpRequest;
var downReq = request(opts, function onResponse(downRes) {
debug('response received');
forEach(downRes.headers, function forwardResponseHeaderUp(value, name) {
upRes.setHeader(name, value);
});
downRes.pipe(upRes);
downRes.on('error', function forwardResponseErrorUp(error) {
upRes.emit('error', error);
});
});
upReq.pipe(downReq);
downReq.on('error', function forwardRequestErrorUp(error) {
upReq.emit('error', error);
});
upReq.on('close', function forwardRequestAbortionDown() {
downReq.abort();
});
}
module.exports = proxyRequest;

View File

@@ -1,4 +1,5 @@
{EventEmitter: $EventEmitter} = require 'events'
{format: $formatUrl, parse: $parseUrl} = require 'url'
$Bluebird = require 'bluebird'
$debug = (require 'debug') 'xo:xo'
@@ -16,6 +17,7 @@ $Promise = require 'bluebird'
$Connection = require './connection'
$Model = require './model'
$proxyRequest = require './proxy-request'
$RedisCollection = require './collection/redis'
$spec = require './spec'
$XAPI = require './xapi'
@@ -408,27 +410,29 @@ class $XO extends $EventEmitter
return connection
registerProxyRequest: (opts) ->
registerProxyRequest: $coroutine (opts) ->
url = "/#{$wait $generateToken()}"
protocol = opts.protocol ? 'http'
if $isString opts
opts = $parseUrl opts
opts.method = if opts.method?
opts.method.toUpperCase()
else
'GET'
opts.createdAt = Date.now()
@_proxyRequests[url] =
host: opts.host
method: opts.method ? 'get'
port: opts.port ? if protocol is 'https' then 443 else 80
protocol: protocol
@_proxyRequests[url] = opts
return url
handleProxyRequest: (req, res, next) ->
unless req.method is 'get' and (request = @_proxyRequests[req.url])
unless (
(request = @_proxyRequests[req.url]) and
req.method is request.method
)
return next()
console.log request
next()
# TODO
$proxyRequest request, req, res
return