UNPKG

3.17 kBPlain TextView Raw
1/*
2 * Copyright 2020 gRPC authors.
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 *
16 */
17
18export interface GrpcUri {
19 scheme?: string;
20 authority?: string;
21 path: string;
22}
23
24/*
25 * The groups correspond to URI parts as follows:
26 * 1. scheme
27 * 2. authority
28 * 3. path
29 */
30const URI_REGEX = /^(?:([A-Za-z0-9+.-]+):)?(?:\/\/([^/]*)\/)?(.+)$/;
31
32export function parseUri(uriString: string): GrpcUri | null {
33 const parsedUri = URI_REGEX.exec(uriString);
34 if (parsedUri === null) {
35 return null;
36 }
37 return {
38 scheme: parsedUri[1],
39 authority: parsedUri[2],
40 path: parsedUri[3],
41 };
42}
43
44export interface HostPort {
45 host: string;
46 port?: number;
47}
48
49const NUMBER_REGEX = /^\d+$/;
50
51export function splitHostPort(path: string): HostPort | null {
52 if (path.startsWith('[')) {
53 const hostEnd = path.indexOf(']');
54 if (hostEnd === -1) {
55 return null;
56 }
57 const host = path.substring(1, hostEnd);
58 /* Only an IPv6 address should be in bracketed notation, and an IPv6
59 * address should have at least one colon */
60 if (host.indexOf(':') === -1) {
61 return null;
62 }
63 if (path.length > hostEnd + 1) {
64 if (path[hostEnd + 1] === ':') {
65 const portString = path.substring(hostEnd + 2);
66 if (NUMBER_REGEX.test(portString)) {
67 return {
68 host: host,
69 port: +portString,
70 };
71 } else {
72 return null;
73 }
74 } else {
75 return null;
76 }
77 } else {
78 return {
79 host,
80 };
81 }
82 } else {
83 const splitPath = path.split(':');
84 /* Exactly one colon means that this is host:port. Zero colons means that
85 * there is no port. And multiple colons means that this is a bare IPv6
86 * address with no port */
87 if (splitPath.length === 2) {
88 if (NUMBER_REGEX.test(splitPath[1])) {
89 return {
90 host: splitPath[0],
91 port: +splitPath[1],
92 };
93 } else {
94 return null;
95 }
96 } else {
97 return {
98 host: path,
99 };
100 }
101 }
102}
103
104export function combineHostPort(hostPort: HostPort): string {
105 if (hostPort.port === undefined) {
106 return hostPort.host;
107 } else {
108 // Only an IPv6 host should include a colon
109 if (hostPort.host.includes(':')) {
110 return `[${hostPort.host}]:${hostPort.port}`;
111 } else {
112 return `${hostPort.host}:${hostPort.port}`;
113 }
114 }
115}
116
117export function uriToString(uri: GrpcUri): string {
118 let result = '';
119 if (uri.scheme !== undefined) {
120 result += uri.scheme + ':';
121 }
122 if (uri.authority !== undefined) {
123 result += '//' + uri.authority + '/';
124 }
125 result += uri.path;
126 return result;
127}