diff --git a/TransportHTTP.js b/TransportHTTP.js index c8a7347..7264fd0 100644 --- a/TransportHTTP.js +++ b/TransportHTTP.js @@ -88,6 +88,8 @@ class TransportHTTP extends Transport { */ //if (!(url && url.includes(':') )) // throw new errors.CodingError("TransportHTTP.p_rawfetch bad url: "+url); + if (url.href.includes('contenthash//')) + console.error("XXX@91",url) if (((typeof url === "string") ? url : url.href).includes('/getall/table')) { throw new Error("Probably dont want to be calling p_rawfetch on a KeyValueTable, especially since dont know if its keyvaluetable or subclass"); //TODO-NAMING return { // I'm not sure what this return would have done - looks half finished to me? diff --git a/dist/dweb-transports-bundle.js b/dist/dweb-transports-bundle.js index 699cd9e..3bec726 100644 --- a/dist/dweb-transports-bundle.js +++ b/dist/dweb-transports-bundle.js @@ -711,7 +711,7 @@ eval("const Url = __webpack_require__(/*! url */ \"../../../../usr/local/lib/nod /*! no static exports found */ /***/ (function(module, exports, __webpack_require__) { -eval("const Transport = __webpack_require__(/*! ./Transport */ \"./Transport.js\"); // Base class for TransportXyz\nconst Transports = __webpack_require__(/*! ./Transports */ \"./Transports.js\"); // Manage all Transports that are loaded\nconst httptools = __webpack_require__(/*! ./httptools */ \"./httptools.js\"); // Expose some of the httptools so that IPFS can use it as a backup\nconst Url = __webpack_require__(/*! url */ \"../../../../usr/local/lib/node_modules/webpack/node_modules/url/url.js\");\n\n\ndefaulthttpoptions = {\n urlbase: 'https://dweb.me:443'\n};\n\nservercommands = { // What the server wants to see to return each of these\n rawfetch: \"contenthash\", // was content/rawfetch which should still work.\n rawstore: \"contenturl/rawstore\",\n rawadd: \"void/rawadd\",\n rawlist: \"metadata/rawlist\",\n get: \"get/table\",\n set: \"set/table\",\n delete: \"delete/table\",\n keys: \"keys/table\",\n getall: \"getall/table\"\n};\n\n\nclass TransportHTTP extends Transport {\n\n constructor(options, verbose) {\n super(options, verbose);\n this.options = options;\n this.urlbase = options.http.urlbase;\n this.supportURLs = ['contenthash', 'http','https'];\n this.supportFunctions = ['fetch', 'store', 'add', 'list', 'reverse', 'newlisturls', \"get\", \"set\", \"keys\", \"getall\", \"delete\", \"newtable\", \"newdatabase\"]; //Does not support: listmonitor - reverse is disabled somewhere not sure if here or caller\n this.supportFeatures = ['fetch.range']\n this.name = \"HTTP\"; // For console log etc\n this.status = Transport.STATUS_LOADED;\n }\n\n static setup0(options, verbose) {\n let combinedoptions = Transport.mergeoptions({ http: defaulthttpoptions },options);\n try {\n let t = new TransportHTTP(combinedoptions, verbose);\n Transports.addtransport(t);\n return t;\n } catch (err) {\n console.log(\"Exception thrown in TransportHTTP.p_setup\", err.message);\n throw err;\n }\n }\n async p_setup1(verbose, cb) {\n this.status = Transport.STATUS_STARTING;\n if (cb) cb(this);\n await this.p_status(verbose);\n if (cb) cb(this);\n return this;\n }\n\n async p_status(verbose) {\n /*\n Return a numeric code for the status of a transport.\n */\n try {\n this.info = await this.p_info(verbose);\n this.status = Transport.STATUS_CONNECTED;\n } catch(err) {\n console.log(this.name, \": Error in p_status.info\",err.message);\n this.status = Transport.STATUS_FAILED;\n }\n return super.p_status(verbose);\n }\n\n _cmdurl(command) {\n return `${this.urlbase}/${command}`\n }\n _url(url, command, parmstr) {\n if (!url) throw new errors.CodingError(`${command}: requires url`);\n if (typeof url !== \"string\") { url = url.href }\n url = url.replace('contenthash:/contenthash', this._cmdurl(command)) ; // Note leaves http: and https: urls unchanged\n url = url.replace('getall/table', command);\n url = url + (parmstr ? \"?\"+parmstr : \"\");\n return url;\n }\n async p_rawfetch(url, opts={}) {\n /*\n Fetch from underlying transport,\n Fetch is used both for contenthash requests and table as when passed to SmartDict.p_fetch may not know what we have\n url: Of resource - which is turned into the HTTP url in p_httpfetch\n opts: {start, end, verbose} see p_GET for documentation\n throws: TransportError if fails\n */\n //if (!(url && url.includes(':') ))\n // throw new errors.CodingError(\"TransportHTTP.p_rawfetch bad url: \"+url);\n if (((typeof url === \"string\") ? url : url.href).includes('/getall/table')) {\n throw new Error(\"Probably dont want to be calling p_rawfetch on a KeyValueTable, especially since dont know if its keyvaluetable or subclass\"); //TODO-NAMING\n return { // I'm not sure what this return would have done - looks half finished to me?\n table: \"keyvaluetable\",\n }\n } else {\n return await httptools.p_GET(this._url(url, servercommands.rawfetch), opts);\n }\n }\n\n p_rawlist(url, {verbose=false}={}) {\n // obj being loaded\n // Locate and return a block, based on its url\n if (!url) throw new errors.CodingError(\"TransportHTTP.p_rawlist: requires url\");\n return httptools.p_GET(this._url(url, servercommands.rawlist), {verbose});\n }\n rawreverse() { throw new errors.ToBeImplementedError(\"Undefined function TransportHTTP.rawreverse\"); }\n\n async p_rawstore(data, {verbose=false}={}) {\n /*\n Store data on http server,\n data: string\n resolves to: {string}: url\n throws: TransportError on failure in p_POST > p_httpfetch\n */\n //PY: res = self._sendGetPost(True, \"rawstore\", headers={\"Content-Type\": \"application/octet-stream\"}, urlargs=[], data=data, verbose=verbose)\n console.assert(data, \"TransportHttp.p_rawstore: requires data\");\n let res = await httptools.p_POST(this._cmdurl(servercommands.rawstore), \"application/octet-stream\", data, verbose); // resolves to URL\n let parsedurl = Url.parse(res);\n let pathparts = parsedurl.pathname.split('/');\n return `contenthash:/contenthash/${pathparts.slice(-1)}`\n\n }\n\n p_rawadd(url, sig, {verbose=false}={}) {\n //verbose=true;\n if (!url || !sig) throw new errors.CodingError(\"TransportHTTP.p_rawadd: invalid parms\",url, sig);\n if (verbose) console.log(\"rawadd\", url, sig);\n let value = JSON.stringify(sig.preflight(Object.assign({},sig)))+\"\\n\";\n return httptools.p_POST(this._url(url, servercommands.rawadd), \"application/json\", value, verbose); // Returns immediately\n }\n\n p_newlisturls(cl, {verbose=false}={}) {\n let u = cl._publicurls.map(urlstr => Url.parse(urlstr))\n .find(parsedurl =>\n ((parsedurl.protocol === \"https:\" && [\"gateway.dweb.me\", \"dweb.me\"].includes(parsedurl.host)\n && (parsedurl.pathname.includes('/content/rawfetch') || parsedurl.pathname.includes('/contenthash/')))\n || (parsedurl.protocol === \"contenthash:\") && (parsedurl.pathname.split('/')[1] === \"contenthash\")));\n if (!u) {\n u = `contenthash:/contenthash/${ cl.keypair.verifyexportmultihashsha256_58() }`; // Pretty random, but means same test will generate same list and server is expecting base58 of a hash\n }\n return [u,u];\n }\n\n // ============================== Key Value support\n\n\n // Support for Key-Value pairs as per\n // https://docs.google.com/document/d/1yfmLRqKPxKwB939wIy9sSaa7GKOzM5PrCZ4W1jRGW6M/edit#\n async p_newdatabase(pubkey, {verbose=false}={}) {\n //if (pubkey instanceof Dweb.PublicPrivate)\n if (pubkey.hasOwnProperty(\"keypair\"))\n pubkey = pubkey.keypair.signingexport()\n // By this point pubkey should be an export of a public key of form xyz:abc where xyz\n // specifies the type of public key (NACL VERIFY being the only kind we expect currently)\n let u = `${this.urlbase}/getall/table/${encodeURIComponent(pubkey)}`;\n return {\"publicurl\": u, \"privateurl\": u};\n }\n\n\n async p_newtable(pubkey, table, {verbose=false}={}) {\n if (!pubkey) throw new errors.CodingError(\"p_newtable currently requires a pubkey\");\n let database = await this.p_newdatabase(pubkey, {verbose});\n // If have use cases without a database, then call p_newdatabase first\n return { privateurl: `${database.privateurl}/${table}`, publicurl: `${database.publicurl}/${table}`} // No action required to create it\n }\n\n //TODO-KEYVALUE needs signing with private key of list\n async p_set(url, keyvalues, value, {verbose=false}={}) { // url = yjs:/yjs/database/table/key\n if (!url || !keyvalues) throw new errors.CodingError(\"TransportHTTP.p_set: invalid parms\",url, keyvalyes);\n if (verbose) console.log(\"p_set\", url, keyvalues, value);\n if (typeof keyvalues === \"string\") {\n let kv = JSON.stringify([{key: keyvalues, value: value}]);\n await httptools.p_POST(this._url(url, servercommands.set), \"application/json\", kv, verbose); // Returns immediately\n } else {\n let kv = JSON.stringify(Object.keys(keyvalues).map((k) => ({\"key\": k, \"value\": keyvalues[k]})));\n await httptools.p_POST(this._url(url, servercommands.set), \"application/json\", kv, verbose); // Returns immediately\n }\n }\n\n _keyparm(key) {\n return `key=${encodeURIComponent(key)}`\n }\n async p_get(url, keys, {verbose=false}={}) {\n if (!url && keys) throw new errors.CodingError(\"TransportHTTP.p_get: requires url and at least one key\");\n let parmstr =Array.isArray(keys) ? keys.map(k => this._keyparm(k)).join('&') : this._keyparm(keys)\n let res = await httptools.p_GET(this._url(url, servercommands.get, parmstr), {verbose});\n return Array.isArray(keys) ? res : res[keys]\n }\n\n async p_delete(url, keys, {verbose=false}={}) {\n if (!url && keys) throw new errors.CodingError(\"TransportHTTP.p_get: requires url and at least one key\");\n let parmstr = keys.map(k => this._keyparm(k)).join('&');\n await httptools.p_GET(this._url(url, servercommands.delete, parmstr), {verbose});\n }\n\n async p_keys(url, {verbose=false}={}) {\n if (!url && keys) throw new errors.CodingError(\"TransportHTTP.p_get: requires url and at least one key\");\n return await httptools.p_GET(this._url(url, servercommands.keys), {verbose});\n }\n async p_getall(url, {verbose=false}={}) {\n if (!url && keys) throw new errors.CodingError(\"TransportHTTP.p_get: requires url and at least one key\");\n return await httptools.p_GET(this._url(url, servercommands.getall), {verbose});\n }\n /* Make sure doesnt shadow regular p_rawfetch\n async p_rawfetch(url, verbose) {\n return {\n table: \"keyvaluetable\",\n _map: await this.p_getall(url, {verbose})\n }; // Data struc is ok as SmartDict.p_fetch will pass to KVT constructor\n }\n */\n\n p_info(verbose) { return httptools.p_GET(`${this.urlbase}/info`, {verbose}); }\n\n static async p_test(opts={}, verbose=false) {\n if (verbose) {console.log(\"TransportHTTP.test\")}\n try {\n let transport = await this.p_setup(opts, verbose);\n if (verbose) console.log(\"HTTP connected\");\n let res = await transport.p_info(verbose);\n if (verbose) console.log(\"TransportHTTP info=\",res);\n res = await transport.p_status(verbose);\n console.assert(res === Transport.STATUS_CONNECTED);\n await transport.p_test_kvt(\"NACL%20VERIFY\", verbose);\n } catch(err) {\n console.log(\"Exception thrown in TransportHTTP.test:\", err.message);\n throw err;\n }\n }\n\n static async test() {\n return this;\n }\n\n}\nTransports._transportclasses[\"HTTP\"] = TransportHTTP;\nexports = module.exports = TransportHTTP;\n\n\n\n//# sourceURL=webpack:///./TransportHTTP.js?"); +eval("const Transport = __webpack_require__(/*! ./Transport */ \"./Transport.js\"); // Base class for TransportXyz\nconst Transports = __webpack_require__(/*! ./Transports */ \"./Transports.js\"); // Manage all Transports that are loaded\nconst httptools = __webpack_require__(/*! ./httptools */ \"./httptools.js\"); // Expose some of the httptools so that IPFS can use it as a backup\nconst Url = __webpack_require__(/*! url */ \"../../../../usr/local/lib/node_modules/webpack/node_modules/url/url.js\");\n\n\ndefaulthttpoptions = {\n urlbase: 'https://dweb.me:443'\n};\n\nservercommands = { // What the server wants to see to return each of these\n rawfetch: \"contenthash\", // was content/rawfetch which should still work.\n rawstore: \"contenturl/rawstore\",\n rawadd: \"void/rawadd\",\n rawlist: \"metadata/rawlist\",\n get: \"get/table\",\n set: \"set/table\",\n delete: \"delete/table\",\n keys: \"keys/table\",\n getall: \"getall/table\"\n};\n\n\nclass TransportHTTP extends Transport {\n\n constructor(options, verbose) {\n super(options, verbose);\n this.options = options;\n this.urlbase = options.http.urlbase;\n this.supportURLs = ['contenthash', 'http','https'];\n this.supportFunctions = ['fetch', 'store', 'add', 'list', 'reverse', 'newlisturls', \"get\", \"set\", \"keys\", \"getall\", \"delete\", \"newtable\", \"newdatabase\"]; //Does not support: listmonitor - reverse is disabled somewhere not sure if here or caller\n this.supportFeatures = ['fetch.range']\n this.name = \"HTTP\"; // For console log etc\n this.status = Transport.STATUS_LOADED;\n }\n\n static setup0(options, verbose) {\n let combinedoptions = Transport.mergeoptions({ http: defaulthttpoptions },options);\n try {\n let t = new TransportHTTP(combinedoptions, verbose);\n Transports.addtransport(t);\n return t;\n } catch (err) {\n console.log(\"Exception thrown in TransportHTTP.p_setup\", err.message);\n throw err;\n }\n }\n async p_setup1(verbose, cb) {\n this.status = Transport.STATUS_STARTING;\n if (cb) cb(this);\n await this.p_status(verbose);\n if (cb) cb(this);\n return this;\n }\n\n async p_status(verbose) {\n /*\n Return a numeric code for the status of a transport.\n */\n try {\n this.info = await this.p_info(verbose);\n this.status = Transport.STATUS_CONNECTED;\n } catch(err) {\n console.log(this.name, \": Error in p_status.info\",err.message);\n this.status = Transport.STATUS_FAILED;\n }\n return super.p_status(verbose);\n }\n\n _cmdurl(command) {\n return `${this.urlbase}/${command}`\n }\n _url(url, command, parmstr) {\n if (!url) throw new errors.CodingError(`${command}: requires url`);\n if (typeof url !== \"string\") { url = url.href }\n url = url.replace('contenthash:/contenthash', this._cmdurl(command)) ; // Note leaves http: and https: urls unchanged\n url = url.replace('getall/table', command);\n url = url + (parmstr ? \"?\"+parmstr : \"\");\n return url;\n }\n async p_rawfetch(url, opts={}) {\n /*\n Fetch from underlying transport,\n Fetch is used both for contenthash requests and table as when passed to SmartDict.p_fetch may not know what we have\n url: Of resource - which is turned into the HTTP url in p_httpfetch\n opts: {start, end, verbose} see p_GET for documentation\n throws: TransportError if fails\n */\n //if (!(url && url.includes(':') ))\n // throw new errors.CodingError(\"TransportHTTP.p_rawfetch bad url: \"+url);\n if (url.href.includes('contenthash//'))\n console.error(\"XXX@91\",url)\n if (((typeof url === \"string\") ? url : url.href).includes('/getall/table')) {\n throw new Error(\"Probably dont want to be calling p_rawfetch on a KeyValueTable, especially since dont know if its keyvaluetable or subclass\"); //TODO-NAMING\n return { // I'm not sure what this return would have done - looks half finished to me?\n table: \"keyvaluetable\",\n }\n } else {\n return await httptools.p_GET(this._url(url, servercommands.rawfetch), opts);\n }\n }\n\n p_rawlist(url, {verbose=false}={}) {\n // obj being loaded\n // Locate and return a block, based on its url\n if (!url) throw new errors.CodingError(\"TransportHTTP.p_rawlist: requires url\");\n return httptools.p_GET(this._url(url, servercommands.rawlist), {verbose});\n }\n rawreverse() { throw new errors.ToBeImplementedError(\"Undefined function TransportHTTP.rawreverse\"); }\n\n async p_rawstore(data, {verbose=false}={}) {\n /*\n Store data on http server,\n data: string\n resolves to: {string}: url\n throws: TransportError on failure in p_POST > p_httpfetch\n */\n //PY: res = self._sendGetPost(True, \"rawstore\", headers={\"Content-Type\": \"application/octet-stream\"}, urlargs=[], data=data, verbose=verbose)\n console.assert(data, \"TransportHttp.p_rawstore: requires data\");\n let res = await httptools.p_POST(this._cmdurl(servercommands.rawstore), \"application/octet-stream\", data, verbose); // resolves to URL\n let parsedurl = Url.parse(res);\n let pathparts = parsedurl.pathname.split('/');\n return `contenthash:/contenthash/${pathparts.slice(-1)}`\n\n }\n\n p_rawadd(url, sig, {verbose=false}={}) {\n //verbose=true;\n if (!url || !sig) throw new errors.CodingError(\"TransportHTTP.p_rawadd: invalid parms\",url, sig);\n if (verbose) console.log(\"rawadd\", url, sig);\n let value = JSON.stringify(sig.preflight(Object.assign({},sig)))+\"\\n\";\n return httptools.p_POST(this._url(url, servercommands.rawadd), \"application/json\", value, verbose); // Returns immediately\n }\n\n p_newlisturls(cl, {verbose=false}={}) {\n let u = cl._publicurls.map(urlstr => Url.parse(urlstr))\n .find(parsedurl =>\n ((parsedurl.protocol === \"https:\" && [\"gateway.dweb.me\", \"dweb.me\"].includes(parsedurl.host)\n && (parsedurl.pathname.includes('/content/rawfetch') || parsedurl.pathname.includes('/contenthash/')))\n || (parsedurl.protocol === \"contenthash:\") && (parsedurl.pathname.split('/')[1] === \"contenthash\")));\n if (!u) {\n u = `contenthash:/contenthash/${ cl.keypair.verifyexportmultihashsha256_58() }`; // Pretty random, but means same test will generate same list and server is expecting base58 of a hash\n }\n return [u,u];\n }\n\n // ============================== Key Value support\n\n\n // Support for Key-Value pairs as per\n // https://docs.google.com/document/d/1yfmLRqKPxKwB939wIy9sSaa7GKOzM5PrCZ4W1jRGW6M/edit#\n async p_newdatabase(pubkey, {verbose=false}={}) {\n //if (pubkey instanceof Dweb.PublicPrivate)\n if (pubkey.hasOwnProperty(\"keypair\"))\n pubkey = pubkey.keypair.signingexport()\n // By this point pubkey should be an export of a public key of form xyz:abc where xyz\n // specifies the type of public key (NACL VERIFY being the only kind we expect currently)\n let u = `${this.urlbase}/getall/table/${encodeURIComponent(pubkey)}`;\n return {\"publicurl\": u, \"privateurl\": u};\n }\n\n\n async p_newtable(pubkey, table, {verbose=false}={}) {\n if (!pubkey) throw new errors.CodingError(\"p_newtable currently requires a pubkey\");\n let database = await this.p_newdatabase(pubkey, {verbose});\n // If have use cases without a database, then call p_newdatabase first\n return { privateurl: `${database.privateurl}/${table}`, publicurl: `${database.publicurl}/${table}`} // No action required to create it\n }\n\n //TODO-KEYVALUE needs signing with private key of list\n async p_set(url, keyvalues, value, {verbose=false}={}) { // url = yjs:/yjs/database/table/key\n if (!url || !keyvalues) throw new errors.CodingError(\"TransportHTTP.p_set: invalid parms\",url, keyvalyes);\n if (verbose) console.log(\"p_set\", url, keyvalues, value);\n if (typeof keyvalues === \"string\") {\n let kv = JSON.stringify([{key: keyvalues, value: value}]);\n await httptools.p_POST(this._url(url, servercommands.set), \"application/json\", kv, verbose); // Returns immediately\n } else {\n let kv = JSON.stringify(Object.keys(keyvalues).map((k) => ({\"key\": k, \"value\": keyvalues[k]})));\n await httptools.p_POST(this._url(url, servercommands.set), \"application/json\", kv, verbose); // Returns immediately\n }\n }\n\n _keyparm(key) {\n return `key=${encodeURIComponent(key)}`\n }\n async p_get(url, keys, {verbose=false}={}) {\n if (!url && keys) throw new errors.CodingError(\"TransportHTTP.p_get: requires url and at least one key\");\n let parmstr =Array.isArray(keys) ? keys.map(k => this._keyparm(k)).join('&') : this._keyparm(keys)\n let res = await httptools.p_GET(this._url(url, servercommands.get, parmstr), {verbose});\n return Array.isArray(keys) ? res : res[keys]\n }\n\n async p_delete(url, keys, {verbose=false}={}) {\n if (!url && keys) throw new errors.CodingError(\"TransportHTTP.p_get: requires url and at least one key\");\n let parmstr = keys.map(k => this._keyparm(k)).join('&');\n await httptools.p_GET(this._url(url, servercommands.delete, parmstr), {verbose});\n }\n\n async p_keys(url, {verbose=false}={}) {\n if (!url && keys) throw new errors.CodingError(\"TransportHTTP.p_get: requires url and at least one key\");\n return await httptools.p_GET(this._url(url, servercommands.keys), {verbose});\n }\n async p_getall(url, {verbose=false}={}) {\n if (!url && keys) throw new errors.CodingError(\"TransportHTTP.p_get: requires url and at least one key\");\n return await httptools.p_GET(this._url(url, servercommands.getall), {verbose});\n }\n /* Make sure doesnt shadow regular p_rawfetch\n async p_rawfetch(url, verbose) {\n return {\n table: \"keyvaluetable\",\n _map: await this.p_getall(url, {verbose})\n }; // Data struc is ok as SmartDict.p_fetch will pass to KVT constructor\n }\n */\n\n p_info(verbose) { return httptools.p_GET(`${this.urlbase}/info`, {verbose}); }\n\n static async p_test(opts={}, verbose=false) {\n if (verbose) {console.log(\"TransportHTTP.test\")}\n try {\n let transport = await this.p_setup(opts, verbose);\n if (verbose) console.log(\"HTTP connected\");\n let res = await transport.p_info(verbose);\n if (verbose) console.log(\"TransportHTTP info=\",res);\n res = await transport.p_status(verbose);\n console.assert(res === Transport.STATUS_CONNECTED);\n await transport.p_test_kvt(\"NACL%20VERIFY\", verbose);\n } catch(err) {\n console.log(\"Exception thrown in TransportHTTP.test:\", err.message);\n throw err;\n }\n }\n\n static async test() {\n return this;\n }\n\n}\nTransports._transportclasses[\"HTTP\"] = TransportHTTP;\nexports = module.exports = TransportHTTP;\n\n\n\n//# sourceURL=webpack:///./TransportHTTP.js?"); /***/ }),