]> gerrit.simantics Code Review - simantics/district.git/blobdiff - org.simantics.maps.server/node/node-v4.8.0-win-x64/node_modules/npm/node_modules/npm-registry-client/lib/request.js
Adding integrated tile server
[simantics/district.git] / org.simantics.maps.server / node / node-v4.8.0-win-x64 / node_modules / npm / node_modules / npm-registry-client / lib / request.js
diff --git a/org.simantics.maps.server/node/node-v4.8.0-win-x64/node_modules/npm/node_modules/npm-registry-client/lib/request.js b/org.simantics.maps.server/node/node-v4.8.0-win-x64/node_modules/npm/node_modules/npm-registry-client/lib/request.js
new file mode 100644 (file)
index 0000000..04be044
--- /dev/null
@@ -0,0 +1,309 @@
+module.exports = regRequest
+
+// npm: means
+// 1. https
+// 2. send authorization
+// 3. content-type is 'application/json' -- metadata
+//
+var assert = require('assert')
+var url = require('url')
+var zlib = require('zlib')
+var Stream = require('stream').Stream
+var STATUS_CODES = require('http').STATUS_CODES
+
+var request = require('request')
+var once = require('once')
+
+function regRequest (uri, params, cb_) {
+  assert(typeof uri === 'string', 'must pass uri to request')
+  assert(params && typeof params === 'object', 'must pass params to request')
+  assert(typeof cb_ === 'function', 'must pass callback to request')
+
+  params.method = params.method || 'GET'
+  this.log.verbose('request', 'uri', uri)
+
+  // Since there are multiple places where an error could occur,
+  // don't let the cb be called more than once.
+  var cb = once(cb_)
+
+  if (uri.match(/^\/?favicon.ico/)) {
+    return cb(new Error("favicon.ico isn't a package, it's a picture."))
+  }
+
+  var adduserChange = /\/?-\/user\/org\.couchdb\.user:([^/]+)\/-rev/
+  var isUserChange = uri.match(adduserChange)
+  var adduserNew = /\/?-\/user\/org\.couchdb\.user:([^/?]+)$/
+  var isNewUser = uri.match(adduserNew)
+  var alwaysAuth = params.auth && params.auth.alwaysAuth
+  var isDelete = params.method === 'DELETE'
+  var isWrite = params.body || isDelete
+
+  if (isUserChange && !isWrite) {
+    return cb(new Error('trying to change user document without writing(?!)'))
+  }
+
+  // new users can *not* use auth, because they don't *have* auth yet
+  if (isUserChange) {
+    this.log.verbose('request', 'updating existing user; sending authorization')
+    params.authed = true
+  } else if (isNewUser) {
+    this.log.verbose('request', "new user, so can't send auth")
+    params.authed = false
+  } else if (alwaysAuth) {
+    this.log.verbose('request', 'always-auth set; sending authorization')
+    params.authed = true
+  } else if (isWrite) {
+    this.log.verbose('request', 'sending authorization for write operation')
+    params.authed = true
+  } else {
+    // most of the time we don't want to auth
+    this.log.verbose('request', 'no auth needed')
+    params.authed = false
+  }
+
+  var self = this
+  this.attempt(function (operation) {
+    makeRequest.call(self, uri, params, function (er, parsed, raw, response) {
+      if (response) {
+        self.log.verbose('headers', response.headers)
+        if (response.headers['npm-notice']) {
+          self.log.warn('notice', response.headers['npm-notice'])
+        }
+      }
+
+      if (!er || (er.message && er.message.match(/^SSL Error/))) {
+        if (er) er.code = 'ESSL'
+        return cb(er, parsed, raw, response)
+      }
+
+      // Only retry on 408, 5xx or no `response`.
+      var statusCode = response && response.statusCode
+
+      var timeout = statusCode === 408
+      var serverError = statusCode >= 500
+      var statusRetry = !statusCode || timeout || serverError
+      if (er && statusRetry && operation.retry(er)) {
+        self.log.info('retry', 'will retry, error on last attempt: ' + er)
+        return undefined
+      }
+      cb.apply(null, arguments)
+    })
+  })
+}
+
+function makeRequest (uri, params, cb_) {
+  var socket
+  var cb = once(function (er, parsed, raw, response) {
+    if (socket) {
+      // The socket might be returned to a pool for re-use, so don’t keep
+      // the 'error' listener from here attached.
+      socket.removeListener('error', cb)
+    }
+
+    return cb_(er, parsed, raw, response)
+  })
+
+  var parsed = url.parse(uri)
+  var headers = {}
+
+  // metadata should be compressed
+  headers['accept-encoding'] = 'gzip'
+
+  var er = this.authify(params.authed, parsed, headers, params.auth)
+  if (er) return cb_(er)
+
+  var opts = this.initialize(
+    parsed,
+    params.method,
+    'application/json',
+    headers
+  )
+
+  opts.followRedirect = (typeof params.follow === 'boolean' ? params.follow : true)
+  opts.encoding = null // tell request let body be Buffer instance
+
+  if (params.etag) {
+    this.log.verbose('etag', params.etag)
+    headers[params.method === 'GET' ? 'if-none-match' : 'if-match'] = params.etag
+  }
+
+  if (params.lastModified && params.method === 'GET') {
+    this.log.verbose('lastModified', params.lastModified)
+    headers['if-modified-since'] = params.lastModified
+  }
+
+  // figure out wth body is
+  if (params.body) {
+    if (Buffer.isBuffer(params.body)) {
+      opts.body = params.body
+      headers['content-type'] = 'application/json'
+      headers['content-length'] = params.body.length
+    } else if (typeof params.body === 'string') {
+      opts.body = params.body
+      headers['content-type'] = 'application/json'
+      headers['content-length'] = Buffer.byteLength(params.body)
+    } else if (params.body instanceof Stream) {
+      headers['content-type'] = 'application/octet-stream'
+      if (params.body.size) headers['content-length'] = params.body.size
+    } else {
+      delete params.body._etag
+      delete params.body._lastModified
+      opts.json = params.body
+    }
+  }
+
+  this.log.http('request', params.method, parsed.href || '/')
+
+  var done = requestDone.call(this, params.method, uri, cb)
+  var req = request(opts, params.streaming ? undefined : decodeResponseBody(done))
+
+  req.on('error', cb)
+
+  // This should not be necessary, as the HTTP implementation in Node
+  // passes errors occurring on the socket to the request itself. Being overly
+  // cautious comes at a low cost, though.
+  req.on('socket', function (s) {
+    socket = s
+    socket.on('error', cb)
+  })
+
+  if (params.streaming) {
+    req.on('response', function (response) {
+      if (response.statusCode >= 400) {
+        var parts = []
+        response.on('data', function (data) {
+          parts.push(data)
+        })
+        response.on('end', function () {
+          decodeResponseBody(done)(null, response, Buffer.concat(parts))
+        })
+      } else {
+        response.on('end', function () {
+          // don't ever re-use connections that had server errors.
+          // those sockets connect to the Bad Place!
+          if (response.socket && response.statusCode > 500) {
+            response.socket.destroy()
+          }
+        })
+
+        return cb(null, response)
+      }
+    })
+  }
+
+  if (params.body && (params.body instanceof Stream)) {
+    params.body.pipe(req)
+  }
+}
+
+function decodeResponseBody (cb) {
+  return function (er, response, data) {
+    if (er) return cb(er, response, data)
+
+    // don't ever re-use connections that had server errors.
+    // those sockets connect to the Bad Place!
+    if (response.socket && response.statusCode > 500) {
+      response.socket.destroy()
+    }
+
+    if (response.headers['content-encoding'] !== 'gzip') {
+      return cb(er, response, data)
+    }
+
+    zlib.gunzip(data, function (er, buf) {
+      if (er) return cb(er, response, data)
+
+      cb(null, response, buf)
+    })
+  }
+}
+
+// cb(er, parsed, raw, response)
+function requestDone (method, where, cb) {
+  return function (er, response, data) {
+    if (er) return cb(er)
+
+    var urlObj = url.parse(where)
+    if (urlObj.auth) urlObj.auth = '***'
+    this.log.http(response.statusCode, url.format(urlObj))
+
+    if (Buffer.isBuffer(data)) {
+      data = data.toString()
+    }
+
+    var parsed
+    if (data && typeof data === 'string' && response.statusCode !== 304) {
+      try {
+        parsed = JSON.parse(data)
+      } catch (ex) {
+        ex.message += '\n' + data
+        this.log.verbose('bad json', data)
+        this.log.error('registry', 'error parsing json')
+        return cb(ex, null, data, response)
+      }
+    } else if (data) {
+      parsed = data
+      data = JSON.stringify(parsed)
+    }
+
+    // expect data with any error codes
+    if (!data && response.statusCode >= 400) {
+      var code = response.statusCode
+      return cb(
+        makeError(code + ' ' + STATUS_CODES[code], null, code),
+        null,
+        data,
+        response
+      )
+    }
+
+    er = null
+    if (parsed && response.headers.etag) {
+      parsed._etag = response.headers.etag
+    }
+
+    if (parsed && response.headers['last-modified']) {
+      parsed._lastModified = response.headers['last-modified']
+    }
+
+    // for the search endpoint, the 'error' property can be an object
+    if (parsed && parsed.error && typeof parsed.error !== 'object' ||
+        response.statusCode >= 400) {
+      var w = url.parse(where).pathname.substr(1)
+      var name
+      if (!w.match(/^-/)) {
+        w = w.split('/')
+        name = decodeURIComponent(w[w.indexOf('_rewrite') + 1])
+      }
+
+      if (!parsed.error) {
+        er = makeError(
+          'Registry returned ' + response.statusCode +
+          ' for ' + method +
+          ' on ' + where,
+          name,
+          response.statusCode
+        )
+      } else if (name && parsed.error === 'not_found') {
+        er = makeError('404 Not Found: ' + name, name, response.statusCode)
+      } else {
+        er = makeError(
+          parsed.error + ' ' + (parsed.reason || '') + ': ' + (name || w),
+          name,
+          response.statusCode
+        )
+      }
+    }
+    return cb(er, parsed, data, response)
+  }.bind(this)
+}
+
+function makeError (message, name, code) {
+  var er = new Error(message)
+  if (name) er.pkgid = name
+  if (code) {
+    er.statusCode = code
+    er.code = 'E' + code
+  }
+  return er
+}