'use strict'; Object.defineProperty(exports, "__esModule", { value: true }); var _classCallCheck2 = require('babel-runtime/helpers/classCallCheck'); var _classCallCheck3 = _interopRequireDefault(_classCallCheck2); var _uriJs = require('uri-js'); var _util = require('./util'); function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } /** * Copyright (c) 2002-2018 "Neo4j," * Neo4j Sweden AB [http://neo4j.com] * * This file is part of Neo4j. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ var DEFAULT_BOLT_PORT = 7687; var DEFAULT_HTTP_PORT = 7474; var DEFAULT_HTTPS_PORT = 7473; var Url = function Url(scheme, host, port, hostAndPort, query) { (0, _classCallCheck3.default)(this, Url); /** * Nullable scheme (protocol) of the URL. * Example: 'bolt', 'bolt+routing', 'http', 'https', etc. * @type {string} */ this.scheme = scheme; /** * Nonnull host name or IP address. IPv6 not wrapped in square brackets. * Example: 'neo4j.com', 'localhost', '127.0.0.1', '192.168.10.15', '::1', '2001:4860:4860::8844', etc. * @type {string} */ this.host = host; /** * Nonnull number representing port. Default port for the given scheme is used if given URL string * does not contain port. Example: 7687 for bolt, 7474 for HTTP and 7473 for HTTPS. * @type {number} */ this.port = port; /** * Nonnull host name or IP address plus port, separated by ':'. IPv6 wrapped in square brackets. * Example: 'neo4j.com', 'neo4j.com:7687', '127.0.0.1', '127.0.0.1:8080', '[2001:4860:4860::8844]', * '[2001:4860:4860::8844]:9090', etc. * @type {string} */ this.hostAndPort = hostAndPort; /** * Nonnull object representing parsed query string key-value pairs. Duplicated keys not supported. * Example: '{}', '{'key1': 'value1', 'key2': 'value2'}', etc. * @type {object} */ this.query = query; }; function parseDatabaseUrl(url) { (0, _util.assertString)(url, 'URL'); var sanitized = sanitizeUrl(url); var parsedUrl = (0, _uriJs.parse)(sanitized.url); var scheme = sanitized.schemeMissing ? null : extractScheme(parsedUrl.scheme); var host = extractHost(parsedUrl.host); // no square brackets for IPv6 var formattedHost = formatHost(host); // has square brackets for IPv6 var port = extractPort(parsedUrl.port, scheme); var hostAndPort = formattedHost + ':' + port; var query = extractQuery(parsedUrl.query, url); return new Url(scheme, host, port, hostAndPort, query); } function sanitizeUrl(url) { url = url.trim(); if (url.indexOf('://') === -1) { // url does not contain scheme, add dummy 'none://' to make parser work correctly return { schemeMissing: true, url: 'none://' + url }; } return { schemeMissing: false, url: url }; } function extractScheme(scheme) { if (scheme) { scheme = scheme.trim(); if (scheme.charAt(scheme.length - 1) === ':') { scheme = scheme.substring(0, scheme.length - 1); } return scheme; } return null; } function extractHost(host, url) { if (!host) { throw new Error('Unable to extract host from ' + url); } return host.trim(); } function extractPort(portString, scheme) { var port = parseInt(portString, 10); return port === 0 || port ? port : defaultPortForScheme(scheme); } function extractQuery(queryString, url) { var query = trimAndSanitizeQuery(queryString); var context = {}; if (query) { query.split('&').forEach(function (pair) { var keyValue = pair.split('='); if (keyValue.length !== 2) { throw new Error('Invalid parameters: \'' + keyValue + '\' in URL \'' + url + '\'.'); } var key = trimAndVerifyQueryElement(keyValue[0], 'key', url); var value = trimAndVerifyQueryElement(keyValue[1], 'value', url); if (context[key]) { throw new Error('Duplicated query parameters with key \'' + key + '\' in URL \'' + url + '\''); } context[key] = value; }); } return context; } function trimAndSanitizeQuery(query) { query = (query || '').trim(); if (query && query.charAt(0) === '?') { query = query.substring(1, query.length); } return query; } function trimAndVerifyQueryElement(element, name, url) { element = (element || '').trim(); if (!element) { throw new Error('Illegal empty ' + name + ' in URL query \'' + url + '\''); } return element; } function escapeIPv6Address(address) { var startsWithSquareBracket = address.charAt(0) === '['; var endsWithSquareBracket = address.charAt(address.length - 1) === ']'; if (!startsWithSquareBracket && !endsWithSquareBracket) { return '[' + address + ']'; } else if (startsWithSquareBracket && endsWithSquareBracket) { return address; } else { throw new Error('Illegal IPv6 address ' + address); } } function formatHost(host) { if (!host) { throw new Error('Illegal host ' + host); } var isIPv6Address = host.indexOf(':') >= 0; return isIPv6Address ? escapeIPv6Address(host) : host; } function formatIPv4Address(address, port) { return address + ':' + port; } function formatIPv6Address(address, port) { var escapedAddress = escapeIPv6Address(address); return escapedAddress + ':' + port; } function defaultPortForScheme(scheme) { if (scheme === 'http') { return DEFAULT_HTTP_PORT; } else if (scheme === 'https') { return DEFAULT_HTTPS_PORT; } else { return DEFAULT_BOLT_PORT; } } exports.default = { parseDatabaseUrl: parseDatabaseUrl, defaultPortForScheme: defaultPortForScheme, formatIPv4Address: formatIPv4Address, formatIPv6Address: formatIPv6Address };