Permalink
Browse files

support intelligent path resolution

  • Loading branch information...
1 parent 251db6a commit 38486b481bc9b55fe8cd272f3794c8c561bfb50c @maxogden committed Mar 22, 2012
Showing with 75 additions and 57 deletions.
  1. +7 −7 README.md
  2. +41 −13 index.js
  3. +1 −1 package.json
  4. +26 −36 test/index.js
View
14 README.md
@@ -56,16 +56,16 @@ the callback is in the form `callback(err)` and must be called for the request t
new Rewriter(t, rewrites)
-there is also a shorthand for querying the couch view server (start to: with _ and pass in the design document URL):
+there is also a shorthand for specifying a `root` url that will be used in all absolute `to` rewrites (ones that begin with a forward slash e.g. `to: "/hello"`). conversely, all relative rewrites (no forward slash at the beginning e.g. `to: "hello.html"`) will be routed to the `attachments` directory
var rewrites = [
- {from:"/api/applications/:dataset", to:"_view/applications", query:{endkey:":dataset", startkey:":dataset", include_docs:"true", descending: "true"}}
- , {from:"/api/applications", to:"_view/applications", query:{include_docs:"true", descending: "true"}}
- , {from:"/api/applications/user/:user", to:"_view/applications_by_user", query:{endkey:":user", startkey:":user", include_docs:"true", descending: "true"}}
- , {from:"/api/datasets/:user", to:"_view/by_user", query:{endkey: [":user",null], startkey:[":user",{}], include_docs:"true", descending: "true"}}
- , {from:"/api/datasets", to:"_view/by_date", query:{include_docs:"true", descending: "true"}}
+ {from:"/api/applications/:dataset", to:"/_view/applications", query:{endkey:":dataset", startkey:":dataset", include_docs:"true", descending: "true"}}
+ , {from:"/api/applications", to:"/_view/applications", query:{include_docs:"true", descending: "true"}}
+ , {from:"/api/applications/user/:user", to:"/_view/applications_by_user", query:{endkey:":user", startkey:":user", include_docs:"true", descending: "true"}}
+ , {from:"/api/datasets/:user", to:"/_view/by_user", query:{endkey: [":user",null], startkey:[":user",{}], include_docs:"true", descending: "true"}}
+ , {from:"/api/datasets", to:"/_view/by_date", query:{include_docs:"true", descending: "true"}}
]
- new Rewriter(t, rewrites, {ddoc: "http://localhost:5984/mydataset/_design/mydesigndocument"})
+ new Rewriter(t, rewrites, {root: "http://localhost:5984/mydataset/_design/mydesigndocument"})
MIT License
View
54 index.js
@@ -12,12 +12,14 @@ function Rewriter(tako, rewrites, options) {
var self = this
if (!options) options = {}
self.opts = _.extend({}, defaults, options)
+
+ rewrites = self.flattenRewrites(rewrites)
+ rewrites = self.validateRewrites(rewrites)
+ rewrites = self.normalizePaths(rewrites)
- _.each(self.flattenRewrites(rewrites), function(rewrite) {
- var to = rewrite.to
- if (_.first(to) === "/") to = _.rest(to).join('')
- if (_.first(to) === '_') return self.proxyCouch(rewrite)
- return self.proxyRequest(rewrite)
+ _.each(rewrites, function(rewrite) {
+ console.log(rewrite.to)
+ self.proxyRequest(rewrite)
})
}
@@ -50,7 +52,6 @@ Rewriter.prototype.createProxy = function(req, resp, proxyOpts, stream) {
}
Rewriter.prototype.route = function(rewrite, callback) {
- if (typeof(rewrite.from) === "undefined") return console.error("NO FROM" + JSON.stringify(rewrite))
var from = rewrite.from
if (_.first(from) !== "/") from = "/" + from
this.tako.route(from, function(req, resp) {
@@ -101,13 +102,6 @@ Rewriter.prototype.proxyRequest = function(rewrite) {
})
}
-Rewriter.prototype.proxyCouch = function(rewrite) {
- this.proxyRequest(_.extend({}, rewrite, {
- to: this.opts.ddoc + rewrite.to,
- json: true
- }))
-}
-
Rewriter.prototype.flattenRewrites = function(rewrites) {
var flattened = []
_.each(rewrites, function(rewrite) {
@@ -122,4 +116,38 @@ Rewriter.prototype.flattenRewrites = function(rewrites) {
return flattened
}
+Rewriter.prototype.validateRewrites = function(rewrites) {
+ var baseURL = this.opts.root
+ var okay = []
+ _.each(rewrites, function(rewrite) {
+ if (!rewrite.from) return console.error({rewrite: rewrite, error: "rewrite.from is missing"})
+ if (!rewrite.to) return console.error({rewrite: rewrite, error: "rewrite.to is missing"})
+ if (!url.parse(rewrite.to).protocol && !baseURL) {
+ return console.error({to: rewrite.to, error: "Must set baseURL to use relative to:"})
+ }
+ return okay.push(rewrite)
+ })
+ return okay
+}
+
+
+Rewriter.prototype.normalizePaths = function(rewrites) {
+ var root = this.opts.root
+ var normalized = []
+ _.each(rewrites, function(rewrite) {
+ // dont process relative rewrites... they go to attachments
+ if (_.first(rewrite.to) !== "/") return normalized.push(rewrite)
+
+ // dont process absolute http rewrites either
+ var to = url.parse(rewrite.to)
+ if (to.protocol) return normalized.push(rewrite)
+
+ var baseURL = url.parse(root)
+ baseURL.pathname = path.join(baseURL.path, rewrite.to)
+ rewrite.to = url.format(baseURL)
+ normalized.push(rewrite)
+ })
+ return normalized
+}
+
module.exports = Rewriter
View
2 package.json
@@ -1,7 +1,7 @@
{ "name" : "rewriter"
, "description" : "streaming http + file routing proxy. serve apps easily!"
, "tags" : ["framework", "server", "static", "couch", "couchdb", "nodepointjavascript"]
-, "version" : "0.0.6"
+, "version" : "0.0.8"
, "author" : "Max Ogden <max@maxogden.com>"
, "repository" :
{ "type" : "git"
View
62 test/index.js
@@ -5,48 +5,38 @@ process.logging = logging
var tako = require('tako')
, http = require('http')
, path = require('path')
- , couch = "http://localhost:5984"
, Rewriter = require('../')
, rewrites = [
{ from:"/", to:'pages/index.html', before: function(req, res, cb) { console.log(req.connection.remoteAddress); cb() }}
, { from:"/edit", to:"pages/recline.html"}
, { from:"/edit/*", to:"pages/recline.html"}
- , { from:"/proxy", to: couch + "/_smalldata/"}
- , { from:"/proxy/*", to: couch + "/_smalldata/*"}
- , { from:"/socket.io", to: couch + "/_smalldata/wiki/socket.io"}
- , { from:"/socket.io/*", to: couch + "/_smalldata/wiki/socket.io/*"}
- , { from:"/login", to: couch + "/_smalldata/twitter/auth/twitter"}
- , { from:"/login/callback", to: couch + "/_smalldata/twitter/auth/twitter/callback"}
- , { from:"/logout", to: couch + "/_smalldata/twitter/logout"}
- , { from:"/api/token", to: couch + "/_smalldata/twitter/auth/token"}
- , { from:"/api/upload/*", to: couch + "/_smalldata/upload/*"}
- , { from:"/api/applications/:dataset", to:"_view/applications", query:{endkey:":dataset", startkey:":dataset", include_docs:"true", descending: "true"}}
- , { from:"/api/applications", to:"_view/applications", query:{include_docs:"true", descending: "true"}}
- , { from:"/api/applications/user/:user", to:"_view/applications_by_user", query:{endkey:":user", startkey:":user", include_docs:"true", descending: "true"}}
- , { from:"/api/datasets/:user", to:"_view/by_user", query:{endkey: [":user",null], startkey:[":user",{}], include_docs:"true", descending: "true"}}
- , { from:"/api/datasets", to:"_view/by_date", query:{include_docs:"true", descending: "true"}}
- , { from:"/api/forks/:id", to:"_view/forks", query:{endkey:":id", startkey:":id", include_docs:"true", descending: "true"}}
- , { from:"/api/forks", to:"_view/forks", query:{include_docs:"true", descending: "true"}}
- , { from:"/api/profile/all", to: couch + "/datacouch-users/_design/users/_list/all/users"}
- , { from:"/api/trending", to:"_view/popular", query:{include_docs: "true", descending: "true", limit: "10"}}
- , { from:"/api/templates", to:"_view/templates", query:{include_docs: "true"}}
- , { from:"/api/users/search/:user", to: couch + "/datacouch-users/_design/users/_view/users", query:{startkey:":user", endkey:":user", include_docs: "true"}}
- , { from:"/api/users", to: couch + '/datacouch-users/'}
- , { from:"/api/users/*", to: couch + '/datacouch-users/*'}
- , { from:"/api/couch", to: couch + "/"}
- , { from:"/api/couch/*", to: couch + "/*"}
- , { from:"/api/epsg/:code", to: couch + "/epsg/:code"}
- , { from:"/api", to: couch + "/datacouch"}
- , { from:"/api/*", to: couch + "/datacouch/*"}
- , { from:"/analytics.gif", to: couch + "/_analytics/spacer.gif"}
+ , { from:"/api/applications/:dataset", to:"/_view/applications", query:{endkey:":dataset", startkey:":dataset", include_docs:"true", descending: "true"}}
+ , { from:"/api/applications", to:"/_view/applications", query:{include_docs:"true", descending: "true"}}
+ , { from:"/api/applications/user/:user", to:"/_view/applications_by_user", query:{endkey:":user", startkey:":user", include_docs:"true", descending: "true"}}
+ , { from:"/api/datasets/:user", to:"/_view/by_user", query:{endkey: [":user",null], startkey:[":user",{}], include_docs:"true", descending: "true"}}
+ , { from:"/api/datasets", to:"/_view/by_date", query:{include_docs:"true", descending: "true"}}
+ , { from:"/api/forks/:id", to:"/_view/forks", query:{endkey:":id", startkey:":id", include_docs:"true", descending: "true"}}
+ , { from:"/api/forks", to:"/_view/forks", query:{include_docs:"true", descending: "true"}}
+ , { from:"/api/profile/all", to:"/datacouch-users/_design/users/_list/all/users"}
+ , { from:"/api/trending", to:"/_view/popular", query:{include_docs: "true", descending: "true", limit: "10"}}
+ , { from:"/api/templates", to:"/_view/templates", query:{include_docs: "true"}}
+ , { from:"/api/users/search/:user", to:"/../../../datacouch-users/_design/users/_view/users", query:{startkey:":user", endkey:":user", include_docs: "true"}}
+ , { from:"/api/users", to:'/../../../datacouch-users/'}
+ , { from:"/api/users/*", to:'/../../../datacouch-users/*'}
+ , { from:"/api/couch", to:"/../../../"}
+ , { from:"/api/couch/*", to:"/../../../*"}
+ , { from:"/api/epsg/:code", to:"/../../../epsg/:code"}
+ , { from:"/api", to:"/../../../datacouch"}
+ , { from:"/api/*", to:"/../../../datacouch/*"}
+ , { from:"/analytics.gif", to:"/_analytics/spacer.gif"}
, { before: function(req, res, cb) { console.log(req.connection.remoteAddress); cb() }
, rewrites: [
- {from:"/db/:id/csv", to: couch + '/:id/_design/recline/_list/csv/all'}
- , {from:"/db/:id/json", to: couch + '/:id/_design/recline/_list/bulkDocs/all'}
- , {from:"/db/:id/headers", to: couch + '/:id/_design/recline/_list/array/headers', query: {group: "true"}}
- , {from:"/db/:id/rows", to: couch + '/:id/_design/recline/_view/all'}
- , {from:"/db/:id", to: couch + "/:id/"}
- , {from:"/db/:id/*", to: couch + "/:id/*"}
+ {from:"/db/:id/csv", to:'/../../../:id/_design/recline/_list/csv/all'}
+ , {from:"/db/:id/json", to:'/../../../:id/_design/recline/_list/bulkDocs/all'}
+ , {from:"/db/:id/headers", to:'/../../../:id/_design/recline/_list/array/headers', query: {group: "true"}}
+ , {from:"/db/:id/rows", to:'/../../../:id/_design/recline/_view/all'}
+ , {from:"/db/:id", to:"/../../../:id/"}
+ , {from:"/db/:id/*", to:"/../../../:id/*"}
]
}
, {from:"/:user", to:"pages/index.html"}
@@ -55,6 +45,6 @@ var tako = require('tako')
;
var t = tako()
- new Rewriter(t, rewrites, {attachments: path.resolve(__dirname, 'attachments')})
+ new Rewriter(t, rewrites, {root: "http://localhost:5984/datacouch/_design/datacouch", attachments: path.resolve(__dirname, 'attachments')})
t.httpServer.listen(9999)
console.log('listening on 9999')

0 comments on commit 38486b4

Please sign in to comment.