A => README.md +4 -0
@@ 1,4 @@
+# Key/Value Store
+
+* To store a value POST to the server at /[key] with the data in the body
+* To retrieve a value GET from the server at /[key] and the data will be returned in the body
A => lib/http-server.js +93 -0
@@ 1,93 @@
+/*
+ * How to use:
+ *
+ * const server = require('./http_server.js');
+ *
+ * "path" is an array of path components
+ * e.g. "/hello/world" -> ['hello', 'world']
+ *
+ * "query" is an object of query keys/values
+ *
+ * "body" is the request body in bytes
+ *
+ * server.get(({path, query, body}, {send, redirect}) => send(data, statusCode, contentType));
+ * server.post(({path, query, body}, {send, redirect}) => redirect('/'));
+ *
+ * server.listen(port);
+ */
+
+const http = require('http');
+
+const methods = ['GET', 'HEAD', 'POST', 'PUT', 'DELETE', 'CONNECT', 'OPTIONS', 'TRACE', 'PATCH'];
+const handlers = {};
+
+const server = http.createServer((req, res) => {
+ let {path, query} = parseUrl(req.url);
+
+ let send = (data, statusCode, contentType) => {
+ res.statusCode = statusCode || 200;
+ res.setHeader('Content-Type', contentType || 'text/plain');
+ res.end(data);
+ };
+
+ let redirect = (url) => {
+ res.statusCode = 303;
+ res.setHeader('Location', url);
+ res.end();
+ };
+
+ getBody(req, (body) => {
+ try {
+ let handler = handlers[req.method];
+ if (handler) {
+ handler({path, query, body}, {send, redirect});
+ } else {
+ send('Method Not Allowed', 405);
+ }
+ } catch (e) {
+ console.log(e);
+ send('Internal server error', 500);
+ }
+ });
+});
+
+const export_obj = {
+ listen: (port) => server.listen(port, '127.0.0.1',
+ () => console.log(`HTTP server listening on port ${port}`)),
+ getContentType: (filepath) => {
+ if (filepath.includes('.html')) return 'text/html';
+ if (filepath.includes('.css')) return 'text/css';
+ if (filepath.includes('.js')) return 'application/javascript';
+ return 'text/plain';
+ },
+};
+
+for (let method of methods) {
+ export_obj[method.toLowerCase()] = (handler) => handlers[method] = handler;
+}
+
+module.exports = export_obj;
+
+function parseUrl(url) {
+ let [pathStr, queryStr] = url.split('?', 2);
+
+ let query = {};
+ if (queryStr) queryStr
+ .split('&')
+ .map(x => x.split('='))
+ .map(x => x.map(y => decodeURIComponent(y)))
+ .map(([x, y]) => query[x] = y);
+
+ let path = pathStr
+ .replace(/\.\./g, '') // remove upward relative paths
+ .split('/')
+ .filter(x => x);
+
+ return {path, query};
+}
+
+function getBody(req, callback) {
+ let body = [];
+ req.on('data', (chunk) => body.push(chunk));
+ req.on('end', () => callback(Buffer.concat(body)));
+}
A => server.js +32 -0
@@ 1,32 @@
+#!/usr/local/bin/node
+
+const server = require('./lib/http-server.js');
+
+const PORT = 24673;
+
+let store = new Map();
+
+server.get(({path}, {send}) => {
+ if (!path.length)
+ return send('Bad Request -- No key specified', 400, 'text/plain');
+
+ let key = path[0];
+
+ if (store.has(key)) {
+ return send(store.get(key), 200, 'text/plain');
+ } else {
+ return send('Bad Request -- Key not found', 404, 'text/plain');
+ }
+});
+
+server.post(({path, body}, {send}) => {
+ if (!path.length)
+ return send('Bad Request -- No key specified', 400, 'text/plain');
+
+ let key = path[0];
+
+ store.set(key, String.fromCharCode(...body));
+ return send('OK -- Value saved', 200, 'text/plain');
+});
+
+server.listen(PORT);
A => setup/kvs_nginx +19 -0
@@ 1,19 @@
+server {
+ listen 80;
+ server_name kvs.rjava.net;
+
+ location / {
+ proxy_pass http://localhost:24673;
+ proxy_set_header X-Real-IP $remote_addr;
+ proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
+ proxy_set_header X-Forwarded-Proto https;
+ proxy_set_header Host $http_host;
+ proxy_set_header X-NginX-Proxy true;
+
+ # Enables WS support
+ proxy_http_version 1.1;
+ proxy_set_header Upgrade $http_upgrade;
+ proxy_set_header Connection "upgrade";
+ proxy_redirect off;
+ }
+}
A => setup/kvs_service +15 -0
@@ 1,15 @@
+#!/bin/sh
+#
+
+# PROVIDE: kvs
+
+. /etc/rc.subr
+
+name="kvs"
+rcvar="${name}_enable"
+pidfile="/var/run/${name}.pid"
+command="/usr/sbin/daemon"
+command_args="-c -f -P ${pidfile} -r /home/robert/kvs/server.js"
+
+load_rc_config $name
+run_rc_command "$1"
A => setup/setup_freebsd.sh +16 -0
@@ 1,16 @@
+#/bin/sh
+
+# Requires root privileges
+
+cd /home/robert/kvs
+
+cp ./setup/kvs_service /usr/local/etc/rc.d/kvs
+
+printf '\nkvs_enable="YES"\n' >> /etc/rc.conf
+
+mkdir -p /usr/local/etc/nginx/sites-enabled
+
+cp ./setup/kvs_nginx /usr/local/etc/nginx/sites-enabled/kvs
+
+service kvs start
+service nginx restart