mirror of https://github.com/grpc/grpc-node.git
				
				
				
			Lint and format
This commit is contained in:
		
							parent
							
								
									f012088ecc
								
							
						
					
					
						commit
						a3c1136fb4
					
				|  | @ -1,12 +1,12 @@ | |||
| import {promisify} from 'util' | ||||
| import {Filter, BaseFilter, FilterFactory} from './filter' | ||||
| import {CallCredentials} from './call-credentials' | ||||
| import {Http2Channel} from './channel' | ||||
| import {CallStream} from './call-stream' | ||||
| import {Metadata} from './metadata' | ||||
| import {promisify} from 'util'; | ||||
| 
 | ||||
| import {CallCredentials} from './call-credentials'; | ||||
| import {CallStream} from './call-stream'; | ||||
| import {Http2Channel} from './channel'; | ||||
| import {BaseFilter, Filter, FilterFactory} from './filter'; | ||||
| import {Metadata} from './metadata'; | ||||
| 
 | ||||
| export class CallCredentialsFilter extends BaseFilter implements Filter { | ||||
| 
 | ||||
|   constructor(private readonly credentials: CallCredentials) { | ||||
|     super(); | ||||
|   } | ||||
|  | @ -20,13 +20,15 @@ export class CallCredentialsFilter extends BaseFilter implements Filter { | |||
|   } | ||||
| } | ||||
| 
 | ||||
| export class CallCredentialsFilterFactory implements FilterFactory<CallCredentialsFilter> { | ||||
| export class CallCredentialsFilterFactory implements | ||||
|     FilterFactory<CallCredentialsFilter> { | ||||
|   private readonly credentials: CallCredentials; | ||||
|   constructor(channel: Http2Channel) { | ||||
|     this.credentials = channel.credentials.getCallCredentials(); | ||||
|   } | ||||
| 
 | ||||
|   createFilter(callStream: CallStream): CallCredentialsFilter { | ||||
|     return new CallCredentialsFilter(this.credentials.compose(callStream.getCredentials())); | ||||
|     return new CallCredentialsFilter( | ||||
|         this.credentials.compose(callStream.getCredentials())); | ||||
|   } | ||||
| } | ||||
|  |  | |||
|  | @ -1,10 +1,10 @@ | |||
| import { Metadata } from './metadata'; | ||||
| import {map, reduce} from 'lodash' | ||||
| import {map, reduce} from 'lodash'; | ||||
| 
 | ||||
| export type CallMetadataGenerator = ( | ||||
|   options: Object, | ||||
|   cb: (err: Error | null, metadata?: Metadata) => void | ||||
| ) => void; | ||||
| import {Metadata} from './metadata'; | ||||
| 
 | ||||
| export type CallMetadataGenerator = | ||||
|     (options: Object, cb: (err: Error|null, metadata?: Metadata) => void) => | ||||
|         void; | ||||
| 
 | ||||
| /** | ||||
|  * A class that represents a generic method of adding authentication-related | ||||
|  | @ -25,32 +25,13 @@ export interface CallCredentials { | |||
|   compose(callCredentials: CallCredentials): CallCredentials; | ||||
| } | ||||
| 
 | ||||
| export namespace CallCredentials { | ||||
|   /** | ||||
|    * Creates a new CallCredentials object from a given function that generates | ||||
|    * Metadata objects. | ||||
|    * @param metadataGenerator A function that accepts a set of options, and | ||||
|    * generates a Metadata object based on these options, which is passed back | ||||
|    * to the caller via a supplied (err, metadata) callback. | ||||
|    */ | ||||
|   export function createFromMetadataGenerator( | ||||
|     metadataGenerator: CallMetadataGenerator | ||||
|   ): CallCredentials { | ||||
|     return new SingleCallCredentials(metadataGenerator); | ||||
|   } | ||||
| 
 | ||||
|   export function createEmpty(): CallCredentials { | ||||
|     return new EmptyCallCredentials(); | ||||
|   } | ||||
| } | ||||
| 
 | ||||
| class ComposedCallCredentials implements CallCredentials { | ||||
|   constructor(private creds: CallCredentials[]) {} | ||||
| 
 | ||||
|   async generateMetadata(options: Object): Promise<Metadata> { | ||||
|     let base: Metadata = new Metadata(); | ||||
|     let generated: Metadata[] = await Promise.all(map( | ||||
|       this.creds, (cred) => cred.generateMetadata(options))); | ||||
|     let generated: Metadata[] = await Promise.all( | ||||
|         map(this.creds, (cred) => cred.generateMetadata(options))); | ||||
|     for (let gen of generated) { | ||||
|       base.merge(gen); | ||||
|     } | ||||
|  | @ -83,8 +64,6 @@ class SingleCallCredentials implements CallCredentials{ | |||
| } | ||||
| 
 | ||||
| class EmptyCallCredentials implements CallCredentials { | ||||
|   constructor () {} | ||||
| 
 | ||||
|   async generateMetadata(options: Object): Promise<Metadata> { | ||||
|     return new Metadata(); | ||||
|   } | ||||
|  | @ -93,3 +72,21 @@ class EmptyCallCredentials implements CallCredentials { | |||
|     return other; | ||||
|   } | ||||
| } | ||||
| 
 | ||||
| export namespace CallCredentials { | ||||
|   /** | ||||
|    * Creates a new CallCredentials object from a given function that generates | ||||
|    * Metadata objects. | ||||
|    * @param metadataGenerator A function that accepts a set of options, and | ||||
|    * generates a Metadata object based on these options, which is passed back | ||||
|    * to the caller via a supplied (err, metadata) callback. | ||||
|    */ | ||||
|   export function createFromMetadataGenerator( | ||||
|       metadataGenerator: CallMetadataGenerator): CallCredentials { | ||||
|     return new SingleCallCredentials(metadataGenerator); | ||||
|   } | ||||
| 
 | ||||
|   export function createEmpty(): CallCredentials { | ||||
|     return new EmptyCallCredentials(); | ||||
|   } | ||||
| } | ||||
|  |  | |||
|  | @ -1,18 +1,14 @@ | |||
| import * as stream from 'stream'; | ||||
| 
 | ||||
| import * as http2 from 'http2'; | ||||
| import {Duplex} from 'stream'; | ||||
| 
 | ||||
| import {CallCredentials} from './call-credentials'; | ||||
| import {Status} from './constants'; | ||||
| import {Filter} from './filter'; | ||||
| import {FilterStackFactory} from './filter-stack'; | ||||
| import {Metadata} from './metadata'; | ||||
| import {ObjectDuplex} from './object-stream'; | ||||
| import {Filter} from './filter' | ||||
| import {FilterStackFactory} from './filter-stack'; | ||||
| 
 | ||||
| const { | ||||
|   HTTP2_HEADER_STATUS, | ||||
|   HTTP2_HEADER_CONTENT_TYPE | ||||
| } = http2.constants; | ||||
| const {HTTP2_HEADER_STATUS, HTTP2_HEADER_CONTENT_TYPE} = http2.constants; | ||||
| 
 | ||||
| export type Deadline = Date | number; | ||||
| 
 | ||||
|  | @ -85,21 +81,20 @@ enum ReadState { | |||
|   READING_MESSAGE | ||||
| } | ||||
| 
 | ||||
| export class Http2CallStream extends stream.Duplex implements CallStream { | ||||
| 
 | ||||
| export class Http2CallStream extends Duplex implements CallStream { | ||||
|   public filterStack: Filter; | ||||
|   private statusEmitted: boolean = false; | ||||
|   private statusEmitted = false; | ||||
|   private http2Stream: http2.ClientHttp2Stream|null = null; | ||||
|   private pendingRead: boolean = false; | ||||
|   private pendingRead = false; | ||||
|   private pendingWrite: Buffer|null = null; | ||||
|   private pendingWriteCallback: Function|null = null; | ||||
|   private pendingFinalCallback: Function|null = null; | ||||
| 
 | ||||
|   private readState: ReadState = ReadState.NO_DATA; | ||||
|   private readCompressFlag: boolean = false; | ||||
|   private readCompressFlag = false; | ||||
|   private readPartialSize: Buffer = Buffer.alloc(4); | ||||
|   private readSizeRemaining: number = 4; | ||||
|   private readMessageSize: number = 0; | ||||
|   private readSizeRemaining = 4; | ||||
|   private readMessageSize = 0; | ||||
|   private readPartialMessage: Buffer[] = []; | ||||
|   private readMessageRemaining = 0; | ||||
| 
 | ||||
|  | @ -111,7 +106,8 @@ export class Http2CallStream extends stream.Duplex implements CallStream { | |||
|   // This is populated (non-null) if and only if the call has ended
 | ||||
|   private finalStatus: StatusObject|null = null; | ||||
| 
 | ||||
|   constructor(private readonly methodName: string, | ||||
|   constructor( | ||||
|       private readonly methodName: string, | ||||
|       private readonly options: CallStreamOptions, | ||||
|       filterStackFactory: FilterStackFactory) { | ||||
|     super({objectMode: true}); | ||||
|  | @ -163,9 +159,12 @@ export class Http2CallStream extends stream.Duplex implements CallStream { | |||
|           this.cancelWithStatus(Status.UNKNOWN, e.message); | ||||
|           return; | ||||
|         } | ||||
|         this.filterStack.receiveMetadata(Promise.resolve(metadata)).then((finalMetadata) => { | ||||
|         this.filterStack.receiveMetadata(Promise.resolve(metadata)) | ||||
|             .then( | ||||
|                 (finalMetadata) => { | ||||
|                   this.emit('metadata', finalMetadata); | ||||
|         }, (error) => { | ||||
|                 }, | ||||
|                 (error) => { | ||||
|                   this.cancelWithStatus(Status.UNKNOWN, error.message); | ||||
|                 }); | ||||
|       }); | ||||
|  | @ -180,7 +179,7 @@ export class Http2CallStream extends stream.Duplex implements CallStream { | |||
|           } | ||||
|           delete headers['grpc-status']; | ||||
|         } | ||||
|         let details: string = ''; | ||||
|         let details = ''; | ||||
|         if (headers.hasOwnProperty('grpc-message')) { | ||||
|           details = decodeURI(headers['grpc-message']); | ||||
|         } | ||||
|  | @ -191,9 +190,12 @@ export class Http2CallStream extends stream.Duplex implements CallStream { | |||
|           metadata = new Metadata(); | ||||
|         } | ||||
|         let status: StatusObject = {code, details, metadata}; | ||||
|         this.filterStack.receiveTrailers(Promise.resolve(status)).then((finalStatus) => { | ||||
|         this.filterStack.receiveTrailers(Promise.resolve(status)) | ||||
|             .then( | ||||
|                 (finalStatus) => { | ||||
|                   this.endCall(finalStatus); | ||||
|         }, (error) => { | ||||
|                 }, | ||||
|                 (error) => { | ||||
|                   this.endCall({ | ||||
|                     code: Status.INTERNAL, | ||||
|                     details: 'Failed to process received status', | ||||
|  | @ -219,7 +221,9 @@ export class Http2CallStream extends stream.Duplex implements CallStream { | |||
|               break; | ||||
|             case ReadState.READING_SIZE: | ||||
|               toRead = Math.min(data.length - readHead, this.readSizeRemaining); | ||||
|             data.copy(this.readPartialSize, 4 - this.readSizeRemaining, readHead, readHead + toRead); | ||||
|               data.copy( | ||||
|                   this.readPartialSize, 4 - this.readSizeRemaining, readHead, | ||||
|                   readHead + toRead); | ||||
|               this.readSizeRemaining -= toRead; | ||||
|               readHead += toRead; | ||||
|               // readSizeRemaining >=0 here
 | ||||
|  | @ -230,14 +234,17 @@ export class Http2CallStream extends stream.Duplex implements CallStream { | |||
|               } | ||||
|               break; | ||||
|             case ReadState.READING_MESSAGE: | ||||
|             toRead = Math.min(data.length - readHead, this.readMessageRemaining); | ||||
|             this.readPartialMessage.push(data.slice(readHead, readHead + toRead)); | ||||
|               toRead = | ||||
|                   Math.min(data.length - readHead, this.readMessageRemaining); | ||||
|               this.readPartialMessage.push( | ||||
|                   data.slice(readHead, readHead + toRead)); | ||||
|               this.readMessageRemaining -= toRead; | ||||
|               readHead += toRead; | ||||
|               // readMessageRemaining >=0 here
 | ||||
|               if (this.readMessageRemaining === 0) { | ||||
|                 // At this point, we have read a full message
 | ||||
|               const messageBytes = Buffer.concat(this.readPartialMessage, this.readMessageSize); | ||||
|                 const messageBytes = Buffer.concat( | ||||
|                     this.readPartialMessage, this.readMessageSize); | ||||
|                 // TODO(murgatroid99): Add receive message filters
 | ||||
|                 if (canPush) { | ||||
|                   if (!this.push(messageBytes)) { | ||||
|  | @ -261,7 +268,7 @@ export class Http2CallStream extends stream.Duplex implements CallStream { | |||
|       }); | ||||
|       stream.on('streamClosed', (errorCode) => { | ||||
|         let code: Status; | ||||
|         let details: string = ''; | ||||
|         let details = ''; | ||||
|         switch (errorCode) { | ||||
|           case http2.constants.NGHTTP2_REFUSED_STREAM: | ||||
|             code = Status.UNAVAILABLE; | ||||
|  | @ -280,11 +287,7 @@ export class Http2CallStream extends stream.Duplex implements CallStream { | |||
|           default: | ||||
|             code = Status.INTERNAL; | ||||
|         } | ||||
|         this.endCall({ | ||||
|           code: code, | ||||
|           details: details, | ||||
|           metadata: new Metadata() | ||||
|         }); | ||||
|         this.endCall({code: code, details: details, metadata: new Metadata()}); | ||||
|       }); | ||||
|       stream.on('error', () => { | ||||
|         this.endCall({ | ||||
|  |  | |||
|  | @ -1,6 +1,7 @@ | |||
| import { CallCredentials } from './call-credentials'; | ||||
| import {createSecureContext, SecureContext} from 'tls'; | ||||
| 
 | ||||
| import {CallCredentials} from './call-credentials'; | ||||
| 
 | ||||
| /** | ||||
|  * A class that contains credentials for communicating over a channel, as well | ||||
|  * as a set of per-call credentials, which are applied to every method call made | ||||
|  | @ -28,39 +29,6 @@ export interface ChannelCredentials { | |||
|   getSecureContext(): SecureContext|null; | ||||
| } | ||||
| 
 | ||||
| export namespace ChannelCredentials { | ||||
|   /** | ||||
|    * Return a new ChannelCredentials instance with a given set of credentials. | ||||
|    * The resulting instance can be used to construct a Channel that communicates | ||||
|    * over TLS. | ||||
|    * @param rootCerts The root certificate data. | ||||
|    * @param privateKey The client certificate private key, if available. | ||||
|    * @param certChain The client certificate key chain, if available. | ||||
|    */ | ||||
|   export function createSsl(rootCerts?: Buffer | null, privateKey?: Buffer | null, certChain?: Buffer | null) : ChannelCredentials { | ||||
|     if (privateKey && !certChain) { | ||||
|       throw new Error('Private key must be given with accompanying certificate chain'); | ||||
|     } | ||||
|     if (!privateKey && certChain) { | ||||
|       throw new Error('Certificate chain must be given with accompanying private key'); | ||||
|     } | ||||
|     const secureContext = createSecureContext({ | ||||
|       ca: rootCerts || undefined, | ||||
|       key: privateKey || undefined, | ||||
|       cert: certChain || undefined | ||||
|     }); | ||||
|     return new SecureChannelCredentialsImpl(secureContext); | ||||
|   } | ||||
| 
 | ||||
|   /** | ||||
|    * Return a new ChannelCredentials instance with no credentials. | ||||
|    */ | ||||
|   export function createInsecure() : ChannelCredentials { | ||||
|     return new InsecureChannelCredentialsImpl(); | ||||
|   } | ||||
| } | ||||
| 
 | ||||
| 
 | ||||
| abstract class ChannelCredentialsImpl implements ChannelCredentials { | ||||
|   protected callCredentials: CallCredentials; | ||||
| 
 | ||||
|  | @ -83,7 +51,7 @@ class InsecureChannelCredentialsImpl extends ChannelCredentialsImpl { | |||
|   } | ||||
| 
 | ||||
|   compose(callCredentials: CallCredentials): ChannelCredentialsImpl { | ||||
|     throw new Error("Cannot compose insecure credentials"); | ||||
|     throw new Error('Cannot compose insecure credentials'); | ||||
|   } | ||||
| 
 | ||||
|   getSecureContext(): SecureContext|null { | ||||
|  | @ -94,21 +62,55 @@ class InsecureChannelCredentialsImpl extends ChannelCredentialsImpl { | |||
| class SecureChannelCredentialsImpl extends ChannelCredentialsImpl { | ||||
|   secureContext: SecureContext; | ||||
| 
 | ||||
|   constructor( | ||||
|     secureContext: SecureContext, | ||||
|     callCredentials?: CallCredentials | ||||
|   ) { | ||||
|   constructor(secureContext: SecureContext, callCredentials?: CallCredentials) { | ||||
|     super(callCredentials); | ||||
|     this.secureContext = secureContext; | ||||
|   } | ||||
| 
 | ||||
|   compose(callCredentials: CallCredentials): ChannelCredentialsImpl { | ||||
|     const combinedCallCredentials = this.callCredentials.compose(callCredentials); | ||||
|     return new SecureChannelCredentialsImpl(this.secureContext, | ||||
|       combinedCallCredentials); | ||||
|     const combinedCallCredentials = | ||||
|         this.callCredentials.compose(callCredentials); | ||||
|     return new SecureChannelCredentialsImpl( | ||||
|         this.secureContext, combinedCallCredentials); | ||||
|   } | ||||
| 
 | ||||
|   getSecureContext(): SecureContext|null { | ||||
|     return this.secureContext; | ||||
|   } | ||||
| } | ||||
| 
 | ||||
| export namespace ChannelCredentials { | ||||
|   /** | ||||
|    * Return a new ChannelCredentials instance with a given set of credentials. | ||||
|    * The resulting instance can be used to construct a Channel that communicates | ||||
|    * over TLS. | ||||
|    * @param rootCerts The root certificate data. | ||||
|    * @param privateKey The client certificate private key, if available. | ||||
|    * @param certChain The client certificate key chain, if available. | ||||
|    */ | ||||
|   export function createSsl( | ||||
|       rootCerts?: Buffer|null, privateKey?: Buffer|null, | ||||
|       certChain?: Buffer|null): ChannelCredentials { | ||||
|     if (privateKey && !certChain) { | ||||
|       throw new Error( | ||||
|           'Private key must be given with accompanying certificate chain'); | ||||
|     } | ||||
|     if (!privateKey && certChain) { | ||||
|       throw new Error( | ||||
|           'Certificate chain must be given with accompanying private key'); | ||||
|     } | ||||
|     const secureContext = createSecureContext({ | ||||
|       ca: rootCerts || undefined, | ||||
|       key: privateKey || undefined, | ||||
|       cert: certChain || undefined | ||||
|     }); | ||||
|     return new SecureChannelCredentialsImpl(secureContext); | ||||
|   } | ||||
| 
 | ||||
|   /** | ||||
|    * Return a new ChannelCredentials instance with no credentials. | ||||
|    */ | ||||
|   export function createInsecure(): ChannelCredentials { | ||||
|     return new InsecureChannelCredentialsImpl(); | ||||
|   } | ||||
| } | ||||
|  |  | |||
|  | @ -1,17 +1,17 @@ | |||
| import {EventEmitter} from 'events'; | ||||
| import {SecureContext} from 'tls'; | ||||
| import * as http2 from 'http2'; | ||||
| import {SecureContext} from 'tls'; | ||||
| import * as url from 'url'; | ||||
| import {CallOptions, CallStreamOptions, CallStream, Http2CallStream} from './call-stream'; | ||||
| import {CallCredentials} from './call-credentials'; | ||||
| import {ChannelCredentials} from './channel-credentials'; | ||||
| import {Metadata, MetadataObject} from './metadata'; | ||||
| import {Status} from './constants' | ||||
| 
 | ||||
| import {FilterStackFactory} from './filter-stack' | ||||
| import {DeadlineFilterFactory} from './deadline-filter' | ||||
| import {CallCredentialsFilterFactory} from './call-credentials-filter' | ||||
| import {CompressionFilterFactory} from './compression-filter' | ||||
| import {CallCredentials} from './call-credentials'; | ||||
| import {CallCredentialsFilterFactory} from './call-credentials-filter'; | ||||
| import {CallOptions, CallStream, CallStreamOptions, Http2CallStream} from './call-stream'; | ||||
| import {ChannelCredentials} from './channel-credentials'; | ||||
| import {CompressionFilterFactory} from './compression-filter'; | ||||
| import {Status} from './constants'; | ||||
| import {DeadlineFilterFactory} from './deadline-filter'; | ||||
| import {FilterStackFactory} from './filter-stack'; | ||||
| import {Metadata, MetadataObject} from './metadata'; | ||||
| 
 | ||||
| const IDLE_TIMEOUT_MS = 300000; | ||||
| 
 | ||||
|  | @ -45,7 +45,8 @@ export enum ConnectivityState { | |||
|  * by a given address. | ||||
|  */ | ||||
| export interface Channel extends EventEmitter { | ||||
|   createStream(methodName: string, metadata: Metadata, options: CallOptions): CallStream; | ||||
|   createStream(methodName: string, metadata: Metadata, options: CallOptions): | ||||
|       CallStream; | ||||
|   connect(callback: () => void): void; | ||||
|   getConnectivityState(): ConnectivityState; | ||||
|   close(): void; | ||||
|  | @ -94,7 +95,7 @@ export class Http2Channel extends EventEmitter implements Channel { | |||
| 
 | ||||
|   private goIdle(): void { | ||||
|     if (this.subChannel !== null) { | ||||
|       this.subChannel.shutdown({graceful: true}, () => {}); | ||||
|       this.subChannel.shutdown({graceful: true}, () => undefined); | ||||
|       this.subChannel = null; | ||||
|     } | ||||
|     this.transitionToState(ConnectivityState.IDLE); | ||||
|  | @ -106,7 +107,8 @@ export class Http2Channel extends EventEmitter implements Channel { | |||
|     } | ||||
|   } | ||||
| 
 | ||||
|   constructor(private readonly address: url.URL, | ||||
|   constructor( | ||||
|       private readonly address: url.URL, | ||||
|       public readonly credentials: ChannelCredentials, | ||||
|       private readonly options: ChannelOptions) { | ||||
|     super(); | ||||
|  | @ -117,15 +119,17 @@ export class Http2Channel extends EventEmitter implements Channel { | |||
|     } | ||||
|     this.filterStackFactory = new FilterStackFactory([ | ||||
|       new CompressionFilterFactory(this), | ||||
|       new CallCredentialsFilterFactory(this), | ||||
|       new DeadlineFilterFactory(this) | ||||
|       new CallCredentialsFilterFactory(this), new DeadlineFilterFactory(this) | ||||
|     ]); | ||||
|   } | ||||
| 
 | ||||
|   private startHttp2Stream(methodName: string, stream: Http2CallStream, metadata: Metadata) { | ||||
|     let finalMetadata: Promise<Metadata> = stream.filterStack.sendMetadata(Promise.resolve(metadata)); | ||||
|   private startHttp2Stream( | ||||
|       methodName: string, stream: Http2CallStream, metadata: Metadata) { | ||||
|     let finalMetadata: Promise<Metadata> = | ||||
|         stream.filterStack.sendMetadata(Promise.resolve(metadata)); | ||||
|     this.connect(() => { | ||||
|       finalMetadata.then((metadataValue) => { | ||||
|       finalMetadata.then( | ||||
|           (metadataValue) => { | ||||
|             let headers = metadataValue.toHttp2Headers(); | ||||
|             headers[HTTP2_HEADER_AUTHORITY] = this.address.hostname; | ||||
|             headers[HTTP2_HEADER_CONTENT_TYPE] = 'application/grpc'; | ||||
|  | @ -138,20 +142,23 @@ export class Http2Channel extends EventEmitter implements Channel { | |||
|                     (this.subChannel as http2.ClientHttp2Session); | ||||
|                 stream.attachHttp2Stream(session.request(headers)); | ||||
|               } else { | ||||
|             /* In this case, we lost the connection while finalizing metadata. | ||||
|              * That should be very unusual */ | ||||
|                 /* In this case, we lost the connection while finalizing | ||||
|                  * metadata. That should be very unusual */ | ||||
|                 setImmediate(() => { | ||||
|                   this.startHttp2Stream(methodName, stream, metadata); | ||||
|                 }); | ||||
|               } | ||||
|             } | ||||
|       }, (error) => { | ||||
|         stream.cancelWithStatus(Status.UNKNOWN, "Failed to generate metadata"); | ||||
|           }, | ||||
|           (error) => { | ||||
|             stream.cancelWithStatus( | ||||
|                 Status.UNKNOWN, 'Failed to generate metadata'); | ||||
|           }); | ||||
|     }); | ||||
|   } | ||||
| 
 | ||||
|   createStream(methodName: string, metadata: Metadata, options: CallOptions): CallStream { | ||||
|   createStream(methodName: string, metadata: Metadata, options: CallOptions): | ||||
|       CallStream { | ||||
|     if (this.connectivityState === ConnectivityState.SHUTDOWN) { | ||||
|       throw new Error('Channel has been shut down'); | ||||
|     } | ||||
|  | @ -159,8 +166,9 @@ export class Http2Channel extends EventEmitter implements Channel { | |||
|       deadline: options.deadline === undefined ? Infinity : options.deadline, | ||||
|       credentials: options.credentials || CallCredentials.createEmpty(), | ||||
|       flags: options.flags || 0 | ||||
|     } | ||||
|     let stream: Http2CallStream = new Http2CallStream(methodName, finalOptions, this.filterStackFactory); | ||||
|     }; | ||||
|     let stream: Http2CallStream = | ||||
|         new Http2CallStream(methodName, finalOptions, this.filterStackFactory); | ||||
|     this.startHttp2Stream(methodName, stream, metadata); | ||||
|     return stream; | ||||
|   } | ||||
|  |  | |||
|  | @ -3,7 +3,7 @@ import {URL} from 'url'; | |||
| 
 | ||||
| import {ClientDuplexStream, ClientDuplexStreamImpl, ClientReadableStream, ClientReadableStreamImpl, ClientUnaryCall, ClientUnaryCallImpl, ClientWritableStream, ClientWritableStreamImpl, ServiceError, ServiceErrorImpl} from './call'; | ||||
| import {CallOptions, CallStream, StatusObject, WriteObject} from './call-stream'; | ||||
| import {Channel, Http2Channel, ChannelOptions} from './channel'; | ||||
| import {Channel, ChannelOptions, Http2Channel} from './channel'; | ||||
| import {ChannelCredentials} from './channel-credentials'; | ||||
| import {Status} from './constants'; | ||||
| import {Metadata} from './metadata'; | ||||
|  | @ -34,11 +34,11 @@ export class Client { | |||
|   waitForReady(deadline: Date|number, callback: (error: Error|null) => void): | ||||
|       void { | ||||
|     let cb: (error: Error|null) => void = once(callback); | ||||
|     let callbackCalled: boolean = false; | ||||
|     let callbackCalled = false; | ||||
|     this.channel.connect(() => { | ||||
|       cb(null); | ||||
|     }); | ||||
|     if (deadline != Infinity) { | ||||
|     if (deadline !== Infinity) { | ||||
|       let timeout: number; | ||||
|       let now: number = (new Date).getTime(); | ||||
|       if (deadline instanceof Date) { | ||||
|  |  | |||
|  | @ -1,10 +1,9 @@ | |||
| import {CallStream} from './call-stream' | ||||
| import {Channel} from './channel' | ||||
| import {Filter, BaseFilter, FilterFactory} from './filter' | ||||
| import {Metadata} from './metadata' | ||||
| import {CallStream} from './call-stream'; | ||||
| import {Channel} from './channel'; | ||||
| import {BaseFilter, Filter, FilterFactory} from './filter'; | ||||
| import {Metadata} from './metadata'; | ||||
| 
 | ||||
| export class CompressionFilter extends BaseFilter implements Filter { | ||||
| 
 | ||||
|   async sendMetadata(metadata: Promise<Metadata>): Promise<Metadata> { | ||||
|     const headers: Metadata = await metadata; | ||||
|     headers.set('grpc-encoding', 'identity'); | ||||
|  | @ -20,8 +19,9 @@ export class CompressionFilter extends BaseFilter implements Filter { | |||
|   } | ||||
| } | ||||
| 
 | ||||
| export class CompressionFilterFactory implements FilterFactory<CompressionFilter> { | ||||
|   constructor(channel: Channel) {} | ||||
| export class CompressionFilterFactory implements | ||||
|     FilterFactory<CompressionFilter> { | ||||
|   constructor(private readonly channel: Channel) {} | ||||
|   createFilter(callStream: CallStream): CompressionFilter { | ||||
|     return new CompressionFilter(); | ||||
|   } | ||||
|  |  | |||
|  | @ -1,19 +1,17 @@ | |||
| import {CallStream} from './call-stream' | ||||
| import {Channel, Http2Channel} from './channel' | ||||
| import {Filter, BaseFilter, FilterFactory} from './filter' | ||||
| import {Status} from './constants' | ||||
| import {Metadata} from './metadata' | ||||
| import {CallStream} from './call-stream'; | ||||
| import {Channel, Http2Channel} from './channel'; | ||||
| import {Status} from './constants'; | ||||
| import {BaseFilter, Filter, FilterFactory} from './filter'; | ||||
| import {Metadata} from './metadata'; | ||||
| 
 | ||||
| const units: [string, number][] = [ | ||||
|   ['m', 1], | ||||
|   ['S', 1000], | ||||
|   ['M', 60 * 1000], | ||||
|   ['H', 60 * 60 * 1000] | ||||
| ] | ||||
| const units: [string, number][] = | ||||
|     [['m', 1], ['S', 1000], ['M', 60 * 1000], ['H', 60 * 60 * 1000]]; | ||||
| 
 | ||||
| export class DeadlineFilter extends BaseFilter implements Filter { | ||||
|   private deadline: number; | ||||
|   constructor(private readonly channel: Http2Channel, private readonly callStream: CallStream) { | ||||
|   constructor( | ||||
|       private readonly channel: Http2Channel, | ||||
|       private readonly callStream: CallStream) { | ||||
|     super(); | ||||
|     let callDeadline = callStream.getDeadline(); | ||||
|     if (callDeadline instanceof Date) { | ||||
|  | @ -28,7 +26,8 @@ export class DeadlineFilter extends BaseFilter implements Filter { | |||
|     } | ||||
|     if (this.deadline !== Infinity) { | ||||
|       setTimeout(() => { | ||||
|         callStream.cancelWithStatus(Status.DEADLINE_EXCEEDED, 'Deadline exceeded'); | ||||
|         callStream.cancelWithStatus( | ||||
|             Status.DEADLINE_EXCEEDED, 'Deadline exceeded'); | ||||
|       }, timeout); | ||||
|     } | ||||
|   } | ||||
|  | @ -37,7 +36,8 @@ export class DeadlineFilter extends BaseFilter implements Filter { | |||
|     if (this.deadline === Infinity) { | ||||
|       return await metadata; | ||||
|     } | ||||
|     let timeoutString : Promise<string> = new Promise<string>((resolve, reject) => { | ||||
|     let timeoutString: Promise<string> = | ||||
|         new Promise<string>((resolve, reject) => { | ||||
|           this.channel.connect(() => { | ||||
|             let now = (new Date()).getTime(); | ||||
|             let timeoutMs = this.deadline - now; | ||||
|  |  | |||
|  | @ -1,21 +1,26 @@ | |||
| import {flow, flowRight, map} from 'lodash'; | ||||
| import {Metadata} from './metadata'; | ||||
| import {CallStream, StatusObject} from './call-stream' | ||||
| 
 | ||||
| import {CallStream, StatusObject} from './call-stream'; | ||||
| import {Filter, FilterFactory} from './filter'; | ||||
| import {Metadata} from './metadata'; | ||||
| 
 | ||||
| export class FilterStack implements Filter { | ||||
|   constructor(private readonly filters: Filter[]) {} | ||||
| 
 | ||||
|   sendMetadata(metadata: Promise<Metadata>) { | ||||
|     return flow(map(this.filters, (filter) => filter.sendMetadata.bind(filter)))(metadata); | ||||
|     return flow(map( | ||||
|         this.filters, (filter) => filter.sendMetadata.bind(filter)))(metadata); | ||||
|   } | ||||
| 
 | ||||
|   receiveMetadata(metadata: Promise<Metadata>) { | ||||
|     return flowRight(map(this.filters, (filter) => filter.receiveMetadata.bind(filter)))(metadata); | ||||
|     return flowRight( | ||||
|         map(this.filters, (filter) => filter.receiveMetadata.bind(filter)))( | ||||
|         metadata); | ||||
|   } | ||||
| 
 | ||||
|   receiveTrailers(status: Promise<StatusObject>): Promise<StatusObject> { | ||||
|     return flowRight(map(this.filters, (filter) => filter.receiveTrailers.bind(filter)))(status); | ||||
|     return flowRight(map( | ||||
|         this.filters, (filter) => filter.receiveTrailers.bind(filter)))(status); | ||||
|   } | ||||
| } | ||||
| 
 | ||||
|  | @ -23,6 +28,7 @@ export class FilterStackFactory implements FilterFactory<FilterStack> { | |||
|   constructor(private readonly factories: FilterFactory<any>[]) {} | ||||
| 
 | ||||
|   createFilter(callStream: CallStream): FilterStack { | ||||
|     return new FilterStack(map(this.factories, (factory) => factory.createFilter(callStream))); | ||||
|     return new FilterStack( | ||||
|         map(this.factories, (factory) => factory.createFilter(callStream))); | ||||
|   } | ||||
| } | ||||
|  |  | |||
|  | @ -1,9 +1,10 @@ | |||
| import {Metadata} from './metadata' | ||||
| import {StatusObject, CallStream} from './call-stream' | ||||
| import {CallStream, StatusObject} from './call-stream'; | ||||
| import {Metadata} from './metadata'; | ||||
| 
 | ||||
| /** | ||||
|  * Filter classes represent related per-call logic and state that is primarily | ||||
|  * used to modify incoming and outgoing data */ | ||||
|  * used to modify incoming and outgoing data | ||||
|  */ | ||||
| export interface Filter { | ||||
|   sendMetadata(metadata: Promise<Metadata>): Promise<Metadata>; | ||||
| 
 | ||||
|  |  | |||
|  | @ -1,11 +1,9 @@ | |||
| import { forOwn } from 'lodash'; | ||||
| import * as http2 from 'http2'; | ||||
| import {forOwn} from 'lodash'; | ||||
| 
 | ||||
| export type MetadataValue = string | Buffer; | ||||
| 
 | ||||
| export interface MetadataObject { | ||||
|   [key: string]: Array<MetadataValue>; | ||||
| } | ||||
| export interface MetadataObject { [key: string]: Array<MetadataValue>; } | ||||
| 
 | ||||
| function cloneMetadataObject(repr: MetadataObject): MetadataObject { | ||||
|   const result: MetadataObject = {}; | ||||
|  | @ -54,7 +52,8 @@ function validate(key: string, value?: MetadataValue): void { | |||
|             'keys that don\'t end with \'-bin\' must have String values'); | ||||
|       } | ||||
|       if (!isLegalNonBinaryValue(value)) { | ||||
|         throw new Error('Metadata string value "' + value + | ||||
|         throw new Error( | ||||
|             'Metadata string value "' + value + | ||||
|             '" contains illegal characters'); | ||||
|       } | ||||
|     } | ||||
|  | @ -66,7 +65,6 @@ function validate(key: string, value?: MetadataValue): void { | |||
|  */ | ||||
| export class Metadata { | ||||
|   protected internalRepr: MetadataObject = {}; | ||||
|   constructor() {} | ||||
| 
 | ||||
|   /** | ||||
|    * Sets the given value for the given key by replacing any other values | ||||
|  | @ -195,7 +193,7 @@ export class Metadata { | |||
|         if (Array.isArray(values)) { | ||||
|           values.forEach((value) => { | ||||
|             result.add(key, Buffer.from(value, 'base64')); | ||||
|           }) | ||||
|           }); | ||||
|         } else { | ||||
|           result.add(key, Buffer.from(values, 'base64')); | ||||
|         } | ||||
|  | @ -203,7 +201,7 @@ export class Metadata { | |||
|         if (Array.isArray(values)) { | ||||
|           values.forEach((value) => { | ||||
|             result.add(key, value); | ||||
|           }) | ||||
|           }); | ||||
|         } else { | ||||
|           result.add(key, values); | ||||
|         } | ||||
|  |  | |||
|  | @ -1,4 +1,4 @@ | |||
| import { Readable, Writable, Duplex } from 'stream'; | ||||
| import {Duplex, Readable, Writable} from 'stream'; | ||||
| 
 | ||||
| export interface IntermediateObjectReadable<T> extends Readable { | ||||
|   read(size?: number): any&T; | ||||
|  | @ -44,7 +44,8 @@ export interface ObjectWritable<T> extends IntermediateObjectWritable<T> { | |||
|   end(chunk: T, encoding?: any, cb?: Function): void; | ||||
| } | ||||
| 
 | ||||
| export interface ObjectDuplex<T, U> extends Duplex, ObjectWritable<T>, ObjectReadable<U> { | ||||
| export interface ObjectDuplex<T, U> extends Duplex, ObjectWritable<T>, | ||||
|                                             ObjectReadable<U> { | ||||
|   read(size?: number): U; | ||||
| 
 | ||||
|   _write(chunk: T, encoding: string, callback: Function): void; | ||||
|  |  | |||
|  | @ -1,7 +1,8 @@ | |||
| import { Metadata } from '../src/metadata'; | ||||
| import { CallCredentials, CallMetadataGenerator } from '../src/call-credentials'; | ||||
| import * as assert from 'assert'; | ||||
| 
 | ||||
| import {CallCredentials, CallMetadataGenerator} from '../src/call-credentials'; | ||||
| import {Metadata} from '../src/metadata'; | ||||
| 
 | ||||
| // Metadata generators
 | ||||
| 
 | ||||
| function makeGenerator(props: Array<string>): CallMetadataGenerator { | ||||
|  | @ -13,19 +14,19 @@ function makeGenerator(props: Array<string>): CallMetadataGenerator { | |||
|       } | ||||
|     }); | ||||
|     cb(null, metadata); | ||||
|   } | ||||
|   }; | ||||
| } | ||||
| 
 | ||||
| function makeAfterMsElapsedGenerator(ms: number): CallMetadataGenerator { | ||||
|   return (_options, cb) => { | ||||
|   return (options, cb) => { | ||||
|     const metadata = new Metadata(); | ||||
|     metadata.add('msElapsed', `${ms}`); | ||||
|     setTimeout(() => cb(null, metadata), ms); | ||||
|   }; | ||||
| }; | ||||
| } | ||||
| 
 | ||||
| const generateFromName: CallMetadataGenerator = makeGenerator(['name']); | ||||
| const generateWithError: CallMetadataGenerator = (_options, cb) => | ||||
| const generateWithError: CallMetadataGenerator = (options, cb) => | ||||
|     cb(new Error()); | ||||
| 
 | ||||
| // Tests
 | ||||
|  | @ -33,23 +34,27 @@ const generateWithError: CallMetadataGenerator = (_options, cb) => | |||
| describe('CallCredentials', () => { | ||||
|   describe('createFromMetadataGenerator', () => { | ||||
|     it('should accept a metadata generator', () => { | ||||
|       assert.doesNotThrow(() => | ||||
|         CallCredentials.createFromMetadataGenerator(generateFromName)); | ||||
|       assert.doesNotThrow( | ||||
|           () => CallCredentials.createFromMetadataGenerator(generateFromName)); | ||||
|     }); | ||||
|   }); | ||||
| 
 | ||||
|   describe('compose', () => { | ||||
|     it('should accept a CallCredentials object and return a new object', () => { | ||||
|       const callCredentials1 = CallCredentials.createFromMetadataGenerator(generateFromName); | ||||
|       const callCredentials2 = CallCredentials.createFromMetadataGenerator(generateFromName); | ||||
|       const callCredentials1 = | ||||
|           CallCredentials.createFromMetadataGenerator(generateFromName); | ||||
|       const callCredentials2 = | ||||
|           CallCredentials.createFromMetadataGenerator(generateFromName); | ||||
|       const combinedCredentials = callCredentials1.compose(callCredentials2); | ||||
|       assert.notEqual(combinedCredentials, callCredentials1); | ||||
|       assert.notEqual(combinedCredentials, callCredentials2); | ||||
|     }); | ||||
| 
 | ||||
|     it('should be chainable', () => { | ||||
|       const callCredentials1 = CallCredentials.createFromMetadataGenerator(generateFromName); | ||||
|       const callCredentials2 = CallCredentials.createFromMetadataGenerator(generateFromName); | ||||
|       const callCredentials1 = | ||||
|           CallCredentials.createFromMetadataGenerator(generateFromName); | ||||
|       const callCredentials2 = | ||||
|           CallCredentials.createFromMetadataGenerator(generateFromName); | ||||
|       assert.doesNotThrow(() => { | ||||
|         callCredentials1.compose(callCredentials2) | ||||
|             .compose(callCredentials2) | ||||
|  | @ -61,7 +66,8 @@ describe('CallCredentials', () => { | |||
|   describe('generateMetadata', () => { | ||||
|     it('should call the function passed to createFromMetadataGenerator', | ||||
|        async () => { | ||||
|         const callCredentials = CallCredentials.createFromMetadataGenerator(generateFromName); | ||||
|          const callCredentials = | ||||
|              CallCredentials.createFromMetadataGenerator(generateFromName); | ||||
|          let metadata: Metadata; | ||||
|          try { | ||||
|            metadata = await callCredentials.generateMetadata({name: 'foo'}); | ||||
|  | @ -69,13 +75,12 @@ describe('CallCredentials', () => { | |||
|            throw err; | ||||
|          } | ||||
|          assert.deepEqual(metadata.get('name'), ['foo']); | ||||
|       } | ||||
|     ); | ||||
|        }); | ||||
| 
 | ||||
|     it('should emit an error if the associated metadataGenerator does', | ||||
|        async () => { | ||||
|         const callCredentials = CallCredentials.createFromMetadataGenerator( | ||||
|           generateWithError); | ||||
|          const callCredentials = | ||||
|              CallCredentials.createFromMetadataGenerator(generateWithError); | ||||
|          let metadata: Metadata|null = null; | ||||
|          try { | ||||
|            metadata = await callCredentials.generateMetadata({}); | ||||
|  | @ -83,8 +88,7 @@ describe('CallCredentials', () => { | |||
|            assert.ok(err instanceof Error); | ||||
|          } | ||||
|          assert.strictEqual(metadata, null); | ||||
|       } | ||||
|     ); | ||||
|        }); | ||||
| 
 | ||||
|     it('should combine metadata from multiple generators', async () => { | ||||
|       const [callCreds1, callCreds2, callCreds3, callCreds4] = | ||||
|  | @ -93,23 +97,21 @@ describe('CallCredentials', () => { | |||
|                 makeAfterMsElapsedGenerator(ms); | ||||
|             return CallCredentials.createFromMetadataGenerator(generator); | ||||
|           }); | ||||
|       const testCases = [{ | ||||
|           credentials: callCreds1 | ||||
|             .compose(callCreds2) | ||||
|       const testCases = [ | ||||
|         { | ||||
|           credentials: callCreds1.compose(callCreds2) | ||||
|                            .compose(callCreds3) | ||||
|                            .compose(callCreds4), | ||||
|           expected: ['50', '100', '150', '200'] | ||||
|         }, { | ||||
|           credentials: callCreds4 | ||||
|             .compose(callCreds3 | ||||
|               .compose(callCreds2 | ||||
|                 .compose(callCreds1))), | ||||
|         }, | ||||
|         { | ||||
|           credentials: callCreds4.compose( | ||||
|               callCreds3.compose(callCreds2.compose(callCreds1))), | ||||
|           expected: ['200', '150', '100', '50'] | ||||
|         }, { | ||||
|           credentials: callCreds3 | ||||
|             .compose(callCreds4 | ||||
|               .compose(callCreds1) | ||||
|               .compose(callCreds2)), | ||||
|         }, | ||||
|         { | ||||
|           credentials: callCreds3.compose( | ||||
|               callCreds4.compose(callCreds1).compose(callCreds2)), | ||||
|           expected: ['150', '200', '50', '100'] | ||||
|         } | ||||
|       ]; | ||||
|  |  | |||
|  | @ -1,10 +1,12 @@ | |||
| import * as assert from 'assert'; | ||||
| import { CallCredentials } from '../src/call-credentials'; | ||||
| import { ChannelCredentials } from '../src/channel-credentials'; | ||||
| import { mockFunction, assert2 } from './common'; | ||||
| import * as fs from 'fs'; | ||||
| import {promisify} from 'util'; | ||||
| 
 | ||||
| import {CallCredentials} from '../src/call-credentials'; | ||||
| import {ChannelCredentials} from '../src/channel-credentials'; | ||||
| 
 | ||||
| import {assert2, mockFunction} from './common'; | ||||
| 
 | ||||
| class CallCredentialsMock implements CallCredentials { | ||||
|   child: CallCredentialsMock; | ||||
|   constructor(child?: CallCredentialsMock) { | ||||
|  | @ -32,22 +34,17 @@ class CallCredentialsMock implements CallCredentials { | |||
| 
 | ||||
| const readFile: (...args: any[]) => Promise<Buffer> = promisify(fs.readFile); | ||||
| // A promise which resolves to loaded files in the form { ca, key, cert }
 | ||||
| const pFixtures = Promise.all([ | ||||
|     'ca.pem', | ||||
|     'server1.key', | ||||
|     'server1.pem' | ||||
|   ].map((file) => readFile(`test/fixtures/${file}`)) | ||||
| ).then((result) => { | ||||
|   return { | ||||
|     ca: result[0], | ||||
|     key: result[1], | ||||
|     cert: result[2] | ||||
|   }; | ||||
| const pFixtures = Promise | ||||
|                       .all(['ca.pem', 'server1.key', 'server1.pem'].map( | ||||
|                           (file) => readFile(`test/fixtures/${file}`))) | ||||
|                       .then((result) => { | ||||
|                         return {ca: result[0], key: result[1], cert: result[2]}; | ||||
|                       }); | ||||
| 
 | ||||
| describe('ChannelCredentials Implementation', () => { | ||||
|   describe('createInsecure', () => { | ||||
|     it('should return a ChannelCredentials object with no associated secure context', () => { | ||||
|     it('should return a ChannelCredentials object with no associated secure context', | ||||
|        () => { | ||||
|          const creds = assert2.noThrowAndReturn( | ||||
|              () => ChannelCredentials.createInsecure()); | ||||
|          assert.ok(!creds.getSecureContext()); | ||||
|  | @ -56,15 +53,15 @@ describe('ChannelCredentials Implementation', () => { | |||
| 
 | ||||
|   describe('createSsl', () => { | ||||
|     it('should work when given no arguments', () => { | ||||
|       const creds: ChannelCredentials = assert2.noThrowAndReturn( | ||||
|         () => ChannelCredentials.createSsl()); | ||||
|       const creds: ChannelCredentials = | ||||
|           assert2.noThrowAndReturn(() => ChannelCredentials.createSsl()); | ||||
|       assert.ok(!!creds.getSecureContext()); | ||||
|     }); | ||||
| 
 | ||||
|     it('should work with just a CA override', async () => { | ||||
|       const {ca} = await pFixtures; | ||||
|       const creds = assert2.noThrowAndReturn( | ||||
|         () => ChannelCredentials.createSsl(ca)); | ||||
|       const creds = | ||||
|           assert2.noThrowAndReturn(() => ChannelCredentials.createSsl(ca)); | ||||
|       assert.ok(!!creds.getSecureContext()); | ||||
|     }); | ||||
| 
 | ||||
|  | @ -99,8 +96,7 @@ describe('ChannelCredentials Implementation', () => { | |||
|       const channelCreds = ChannelCredentials.createSsl(); | ||||
|       const callCreds = new CallCredentialsMock(); | ||||
|       const composedChannelCreds = channelCreds.compose(callCreds); | ||||
|       assert.strictEqual(composedChannelCreds.getCallCredentials(), | ||||
|         callCreds); | ||||
|       assert.strictEqual(composedChannelCreds.getCallCredentials(), callCreds); | ||||
|     }); | ||||
| 
 | ||||
|     it('should be chainable', () => { | ||||
|  |  | |||
|  | @ -1,31 +1,30 @@ | |||
| import * as assert from 'assert'; | ||||
| import * as http2 from 'http2'; | ||||
| import {range} from 'lodash'; | ||||
| import * as metadata from '../src/metadata'; | ||||
| import {Metadata} from '../src/metadata'; | ||||
| 
 | ||||
| class Metadata extends metadata.Metadata { | ||||
| class TestMetadata extends Metadata { | ||||
|   getInternalRepresentation() { | ||||
|     return this.internalRepr; | ||||
|   } | ||||
| 
 | ||||
|   static fromHttp2Headers(headers: http2.IncomingHttpHeaders): Metadata { | ||||
|     const result = metadata.Metadata.fromHttp2Headers(headers) as Metadata; | ||||
|   static fromHttp2Headers(headers: http2.IncomingHttpHeaders): TestMetadata { | ||||
|     const result = Metadata.fromHttp2Headers(headers) as TestMetadata; | ||||
|     result.getInternalRepresentation = | ||||
|       Metadata.prototype.getInternalRepresentation; | ||||
|         TestMetadata.prototype.getInternalRepresentation; | ||||
|     return result; | ||||
|   } | ||||
| } | ||||
| 
 | ||||
| const validKeyChars = '0123456789abcdefghijklmnopqrstuvwxyz_-.'; | ||||
| const validNonBinValueChars = range(0x20, 0x7f) | ||||
|   .map(code => String.fromCharCode(code)) | ||||
|   .join(''); | ||||
| const validNonBinValueChars = | ||||
|     range(0x20, 0x7f).map(code => String.fromCharCode(code)).join(''); | ||||
| 
 | ||||
| describe('Metadata', () => { | ||||
|   let metadata: Metadata; | ||||
|   let metadata: TestMetadata; | ||||
| 
 | ||||
|   beforeEach(() => { | ||||
|     metadata = new Metadata(); | ||||
|     metadata = new TestMetadata(); | ||||
|   }); | ||||
| 
 | ||||
|   describe('set', () => { | ||||
|  | @ -178,10 +177,8 @@ describe('Metadata', () => { | |||
|       metadata.add('Key2', 'value2'); | ||||
|       metadata.add('KEY3', 'value3a'); | ||||
|       metadata.add('KEY3', 'value3b'); | ||||
|       assert.deepEqual(metadata.getMap(), | ||||
|                        {key1: 'value1', | ||||
|                         key2: 'value2', | ||||
|                         key3: 'value3a'}); | ||||
|       assert.deepEqual( | ||||
|           metadata.getMap(), {key1: 'value1', key2: 'value2', key3: 'value3a'}); | ||||
|     }); | ||||
|   }); | ||||
| 
 | ||||
|  | @ -213,7 +210,7 @@ describe('Metadata', () => { | |||
|       metadata.add('Key2', 'value2a'); | ||||
|       metadata.add('KEY3', 'value3a'); | ||||
|       metadata.add('key4', 'value4'); | ||||
|       const metadata2 = new Metadata(); | ||||
|       const metadata2 = new TestMetadata(); | ||||
|       metadata2.add('KEY1', 'value1'); | ||||
|       metadata2.add('key2', 'value2b'); | ||||
|       metadata2.add('key3', 'value3b'); | ||||
|  | @ -246,8 +243,7 @@ describe('Metadata', () => { | |||
|         key2: ['value2'], | ||||
|         key3: ['value3a', 'value3b'], | ||||
|         'key-bin': [ | ||||
|           'AAECAwQFBgcICQoLDA0ODw==', | ||||
|           'EBESExQVFhcYGRobHB0eHw==', | ||||
|           'AAECAwQFBgcICQoLDA0ODw==', 'EBESExQVFhcYGRobHB0eHw==', | ||||
|           'AAECAwQFBgcICQoLDA0ODxAREhMUFRYXGBkaGxwdHh8=' | ||||
|         ] | ||||
|       }); | ||||
|  | @ -265,27 +261,25 @@ describe('Metadata', () => { | |||
|         key2: ['value2'], | ||||
|         key3: ['value3a', 'value3b'], | ||||
|         'key-bin': [ | ||||
|           'AAECAwQFBgcICQoLDA0ODw==', | ||||
|           'EBESExQVFhcYGRobHB0eHw==', | ||||
|           'AAECAwQFBgcICQoLDA0ODw==', 'EBESExQVFhcYGRobHB0eHw==', | ||||
|           'AAECAwQFBgcICQoLDA0ODxAREhMUFRYXGBkaGxwdHh8=' | ||||
|         ] | ||||
|       }; | ||||
|       const metadataFromHeaders = Metadata.fromHttp2Headers(headers); | ||||
|       const metadataFromHeaders = TestMetadata.fromHttp2Headers(headers); | ||||
|       const internalRepr = metadataFromHeaders.getInternalRepresentation(); | ||||
|       assert.deepEqual(internalRepr, { | ||||
|         key1: ['value1'], | ||||
|         key2: ['value2'], | ||||
|         key3: ['value3a', 'value3b'], | ||||
|         'key-bin': [ | ||||
|           Buffer.from(range(0, 16)), | ||||
|           Buffer.from(range(16, 32)), | ||||
|           Buffer.from(range(0, 16)), Buffer.from(range(16, 32)), | ||||
|           Buffer.from(range(0, 32)) | ||||
|         ] | ||||
|       }); | ||||
|     }); | ||||
| 
 | ||||
|     it('creates an empty Metadata object from empty headers', () => { | ||||
|       const metadataFromHeaders = Metadata.fromHttp2Headers({}); | ||||
|       const metadataFromHeaders = TestMetadata.fromHttp2Headers({}); | ||||
|       const internalRepr = metadataFromHeaders.getInternalRepresentation(); | ||||
|       assert.deepEqual(internalRepr, {}); | ||||
|     }); | ||||
|  |  | |||
		Loading…
	
		Reference in New Issue