Commits

Anonymous committed 945be30

Initial commit.

  • Participants

Comments (0)

Files changed (6)

+Copyright (c) 2010, Anton Korenyushkin
+
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are
+met:
+
+* Redistributions of source code must retain the above copyright
+  notice, this list of conditions and the following disclaimer.
+
+* Redistributions in binary form must reproduce the above copyright
+  notice, this list of conditions and the following disclaimer in the
+  documentation and/or other materials provided with the distribution.
+
+* Neither the name of the author nor the names of contributors may be
+  used to endorse or promote products derived from this software
+  without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
+CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+# Core Akshell Library
+
+`core` provides wrappers to low-level Akshell functions. It must be
+used in every application.
+// Copyright (c) 2010, Anton Korenyushkin
+// All rights reserved.
+
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are met:
+//     * Redistributions of source code must retain the above copyright
+//       notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above copyright
+//       notice, this list of conditions and the following disclaimer in the
+//       documentation and/or other materials provided with the distribution.
+//     * Neither the name of the author nor the names of contributors may be
+//       used to endorse or promote products derived from this software
+//       without specific prior written permission.
+
+// THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS "AS IS" AND ANY
+// EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+// WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
+// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+// POSSIBILITY OF SUCH DAMAGE.
+
+var inner = require('inner');
+
+
+exports.Type = _core.Type;
+exports.Type.prototype.default_ = exports.Type.prototype._default;
+['integer', 'serial', 'unique', 'foreign', 'check'].forEach(
+  function (name) { inner.publishMethod(name, exports.Type); });
+
+
+exports.number = _core.db.number;
+exports.string = _core.db.string;
+exports.bool = _core.db.bool;
+exports.date = _core.db.date;
+
+
+[
+  'insert',
+  'list',
+  'drop',
+  'rollback',
+  'getHeader',
+  'getInteger',
+  'getSerial',
+  'getDefault',
+  'getUnique',
+  'getForeign'
+].forEach(
+  function (name) {
+    inner.publishFunction(name, _core.db, exports);
+  });
+
+
+exports.query = function (query,
+                          queryParams/* = [] */,
+                          by/* = [] */,
+                          byParams/* = [] */,
+                          start/* = 0 */,
+                          length/* optional */) {
+  return _core.db.query(
+    query,
+    queryParams || [],
+    by ? (by instanceof Array ? by : [by]) : [],
+    byParams || [],
+    start || 0,
+    length);
+};
+
+
+exports.count = function(query, params/* = [] */) {
+  return _core.db.count(query, params || []);
+};
+
+
+exports.create = function (name, header, constrs/* = {} */) {
+  constrs = constrs || {};
+  _core.db.create(name,
+                  header,
+                  constrs.unique || [],
+                  constrs.foreign || [],
+                  constrs.check || []);
+};
+
+
+exports.del = function (name, expr, params/* = [] */) {
+  return _core.db.del(name, expr, params || []);
+};
+
+
+exports.update = function (name,
+                           whereExpr,
+                           whereParams,
+                           updateExprs,
+                           updateParams/* = [] */) {
+  return _core.db.update(name,
+                         whereExpr,
+                         whereParams,
+                         updateExprs,
+                         updateParams || []);
+};
+// Copyright (c) 2010, Anton Korenyushkin
+// All rights reserved.
+
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are met:
+//     * Redistributions of source code must retain the above copyright
+//       notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above copyright
+//       notice, this list of conditions and the following disclaimer in the
+//       documentation and/or other materials provided with the distribution.
+//     * Neither the name of the author nor the names of contributors may be
+//       used to endorse or promote products derived from this software
+//       without specific prior written permission.
+
+// THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS "AS IS" AND ANY
+// EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+// WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
+// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+// POSSIBILITY OF SUCH DAMAGE.
+
+var inner = require('inner');
+
+
+[
+  'read',
+  'exists',
+  'isDir',
+  'isFile',
+  'getModDate',
+  'list',
+  'createDir',
+  'write',
+  'rename'
+].forEach(
+  function (name) {
+    inner.publishFunction(name, _core.fs, exports);
+  });
+
+
+exports.TempFile = _core.TempFile;
+exports.TempFile.prototype.read = function () { return exports.read(this); };
+
+
+exports.remove = function (path) {
+  if (exports.isDir(path)) {
+    var children = exports.list(path);
+    for (var i = 0; i < children.length; ++i)
+      arguments.callee(path + '/' + children[i]);
+  }
+  _core.fs.remove(path);
+};
+// Copyright (c) 2010, Anton Korenyushkin
+// All rights reserved.
+
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are met:
+//     * Redistributions of source code must retain the above copyright
+//       notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above copyright
+//       notice, this list of conditions and the following disclaimer in the
+//       documentation and/or other materials provided with the distribution.
+//     * Neither the name of the author nor the names of contributors may be
+//       used to endorse or promote products derived from this software
+//       without specific prior written permission.
+
+// THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS "AS IS" AND ANY
+// EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+// WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
+// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+// POSSIBILITY OF SUCH DAMAGE.
+
+var inner = require('inner');
+
+
+exports.Global = _core.Global;
+exports.global = this;
+
+
+_core.errors.slice(2).forEach(
+  function (error) {
+    exports[error.prototype.name] = error;
+  });
+
+
+exports.Script = _core.Script;
+inner.publishMethod('run', exports.Script);
+
+
+var Binary = exports.Binary = _core.Binary;
+['toString', 'range', 'fill', 'indexOf', 'lastIndexOf'].forEach(
+  function (name) { inner.publishMethod(name, Binary); });
+
+
+exports.Proxy = _core.Proxy;
+
+
+exports.COMMON = 0;
+exports.READONLY = 1;
+exports.HIDDEN = 2;
+exports.PERMANENT = 4;
+
+
+['set', 'readCode', 'getCodeModDate', 'hash'].forEach(
+  function (name) { inner.publishFunction(name, _core, exports); });
+
+
+exports.construct = function (func, args) {
+  return _core.construct.call(
+    _core,
+    func,
+    args instanceof Array ? args : Array.prototype.slice.call(args));
+};
+
+
+exports.getAdminedApps = function (name) {
+  return _core.db.getAdminedApps(name).sort();
+};
+
+
+exports.getDevelopedApps = function (name) {
+  return _core.db.getDevelopedApps(name).sort();
+};
+
+
+exports.getAppDescription = function (name) {
+  var result = _core.db.getAppDescription(name);
+  result.name = name;
+  result.developers.sort();
+  return result;
+};
+
+
+function getPath(path) {
+  return (path
+          ? (path[0] == '/' ? path : '/' + path)
+          : '/');
+}
+
+
+exports.requestApp = function (appName, request) {
+  var realRequest = {
+    method: request.method || 'get',
+    path: getPath(request.path),
+    get: request.get || {},
+    post: request.post || {},
+    headers: request.headers || {},
+    fileNames: []
+  };
+  var filePathes = [];
+  var files = request.files || {};
+  for (var fileName in files) {
+    realRequest.fileNames.push(fileName);
+    filePathes.push(files[fileName]);
+  }
+  var raw = _core.requestApp(appName,
+                             JSON.stringify(realRequest),
+                             filePathes,
+                             request.data || '');
+  var endOfHead = raw.indexOf('\n\n');
+  if (endOfHead == -1)
+    throw exports.AppRequestError('Response without a head');
+  var content = raw.range(endOfHead + 2);
+  var headerLines = raw.range(0, endOfHead).toString().split('\n');
+  var statusString = headerLines.shift();
+  var status = +statusString;
+  if (!status)
+    throw exports.AppRequestError('Invalid status: "' + statusString + '"');
+  var headers = {};
+  headerLines.forEach(
+    function (headerLine) {
+      var name = headerLine.split(': ', 1)[0];
+      if (name.length == headerLine.length)
+        throw exports.AppRequestError(
+          'Invalid header line: "' + headerLine + '"');
+      headers[name] = headerLine.substr(name.length + 2);
+    });
+  return {
+    content: content,
+    status: status,
+    headers: headers
+  };
+};
+
+
+function encodeParams(params) {
+  var parts = [];
+  for (var name in params) {
+    var values = params[name];
+    if (!(values instanceof Array))
+      values = [values];
+    for (var i = 0; i < values.length; ++i)
+      parts.push(
+        encodeURIComponent(name) + '=' + encodeURIComponent(values[i]));
+  }
+  return parts.join('&');
+}
+
+
+exports.requestHost = function (hostName, request) {
+  var server;
+  var port;
+  var colonIndex = hostName.indexOf(':');
+  if (colonIndex == -1) {
+    server = hostName;
+    port = '80';
+  } else {
+    server = hostName.substr(0, colonIndex);
+    port = hostName.substr(colonIndex + 1);
+  }
+  var requestHeaders = {
+    'Connection': 'close',
+    'Accept-Charset': 'utf-8',
+    'Accept-Encoding': 'identity',
+    'Host': hostName
+  };
+  var data;
+  if (request.data) {
+    if (request.post)
+      throw exports.UsageError('data and post cannot be specified together');
+    data = (request.data instanceof Binary
+            ? request.data
+            : new Binary(request.data));
+  }
+  if (request.post) {
+    data = new Binary(encodeParams(request.post));
+    requestHeaders['Content-Type'] = 'application/x-www-form-urlencoded';
+  }
+  if (data)
+    requestHeaders['Content-Length'] = data.length;
+  for (var name in request.headers || {})
+    requestHeaders[name] = request.headers[name];
+  var path = getPath(request.path);
+  var get = request.get && encodeParams(request.get);
+  if (get)
+    path += '?' + get;
+  var method = request.method ? request.method.toUpperCase() : 'GET';
+  var requestHeaderLines = [method + ' ' + path + ' HTTP/1.1'];
+  for (name in requestHeaders)
+    requestHeaderLines.push(name + ': ' + requestHeaders[name]);
+  requestHeaderLines.push('\r\n');
+  var requestHeader = requestHeaderLines.join('\r\n');
+
+  var raw = _core.requestHost(
+    server,
+    port,
+    data ? new Binary(new Binary(requestHeader), data) : requestHeader);
+
+  var endOfHead = raw.indexOf('\r\n\r\n');
+  if (endOfHead == -1)
+    throw exports.HostRequestError('Unexpected end of response');
+  var content = raw.range(endOfHead + 4);
+  var responseHeaderLines = raw.range(0, endOfHead).toString().split('\r\n');
+  var match = responseHeaderLines.shift().match(/^http\/[^ ]+ ([0-9]+).*$/i);
+  if (!match)
+    throw exports.HostRequestError('Illegal HTTP response status line');
+  var status = +match[1];
+  var responseHeaders = {};
+  var prev;
+  responseHeaderLines.forEach(
+    function (headerLine) {
+      match = headerLine.match(/^([^: \t]+)[ \t]*:[ \t]*(.*?)[ \t]*$/);
+      if (match) {
+        name = match[1];
+        name = (name[0].toUpperCase() +
+                name.substr(1).toLowerCase().replace(
+                  /-[a-z]/g,
+                  function (string) { return '-' + string[1].toUpperCase(); }));
+        if (responseHeaders.hasOwnProperty(name))
+          responseHeaders[name] += ',' + match[2];
+        else
+          responseHeaders[name] = match[2];
+        prev = name;
+      } else if (prev && (match = headerLine.match(/^[ \t]+(.*?)[ \t]*$/))) {
+        responseHeaders[prev] += ' ' + match[1];
+      }
+    });
+  return {
+    content: content,
+    status: status,
+    headers: responseHeaders
+  };
+};
+
+
+exports.db = require('db');
+exports.fs = require('fs');
+
+
+_core.main = function (rawJSON) {
+  var raw = JSON.parse(rawJSON);
+  if (!(typeof(raw) == 'object' &&
+        typeof(raw.method) == 'string' &&
+        typeof(raw.path) == 'string' &&
+        typeof(raw.get) == 'object' &&
+        typeof(raw.post) == 'object' &&
+        typeof(raw.headers) == 'object' &&
+        raw.fileNames instanceof Array &&
+        raw.fileNames.length == _core.files.length))
+    return '400\n\nBad request';
+  var headers = {};
+  for (var name in raw.headers)
+    headers[name.toLowerCase()] = raw.headers[name];
+  var files = {};
+  for (var i = 0; i < _core.files.length; ++i)
+    files[raw.fileNames[i]] = _core.files[i];
+  var request = {
+    method: raw.method.toUpperCase(),
+    scriptName: '',
+    pathInfo: raw.path,
+    queryString: (typeof(raw.fullPath) == 'string'
+                  ? raw.fullPath.substr(raw.path.length + 1)
+                  : ''),
+    host: headers.host,
+    port: 80,
+    scheme: 'http',
+    input: _core.data,
+    headers: headers,
+    jsgi: {
+      version: [0, 3],
+      multithread: false,
+      multiprocess: true,
+      runOnce: false,
+      cgi: false
+    },
+    env: {
+      fullPath: raw.fullPath || raw.path,
+      get: raw.get,
+      post: raw.post,
+      user: _core.user,
+      issuer: _core.issuer,
+      session: raw.session,
+      csrfToken: raw.csrfToken,
+      files: files
+    }
+  };
+  var response = require.main.exports.app(request);
+  var parts = [new Binary(response.status + '\n')];
+  for (name in response.headers)
+    parts.push(new Binary(name + ': ' + response.headers[name] + '\n'));
+  parts.push(new Binary('\n'));
+  response.body.forEach(
+    function (part) {
+      parts.push(part instanceof Binary
+                 ? part
+                 : new Binary(part));
+    });
+  return exports.construct(Binary, parts);
+};
+// Copyright (c) 2010, Anton Korenyushkin
+// All rights reserved.
+
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are met:
+//     * Redistributions of source code must retain the above copyright
+//       notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above copyright
+//       notice, this list of conditions and the following disclaimer in the
+//       documentation and/or other materials provided with the distribution.
+//     * Neither the name of the author nor the names of contributors may be
+//       used to endorse or promote products derived from this software
+//       without specific prior written permission.
+
+// THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS "AS IS" AND ANY
+// EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+// WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
+// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+// POSSIBILITY OF SUCH DAMAGE.
+
+
+exports.publishFunction = function (name, from, to) {
+  var func = from[name];
+  to[name] = function () {
+    return func.apply(from, arguments);
+  };
+};
+
+
+exports.publishMethod = function (name, constructor) {
+  constructor.prototype[name] = constructor.prototype['_' + name];
+};