Skip to content

Commit

Permalink
#296: http improvements
Browse files Browse the repository at this point in the history
  • Loading branch information
petermasking committed Sep 24, 2024
1 parent 8131e3a commit dfd0037
Show file tree
Hide file tree
Showing 6 changed files with 72 additions and 19 deletions.
12 changes: 7 additions & 5 deletions packages/http/src/HttpRemote.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,8 @@ import { ErrorConverter, Request, Response as ResultResponse } from '@jitar/exec
import { Remote } from '@jitar/services';
import { File } from '@jitar/sourcing';

const APPLICATION_JSON = 'application/json';
import HeaderKeys from './definitions/HeaderKeys';
import HeaderValues from './definitions/HeaderValues';

const errorConverter = new ErrorConverter();

Expand Down Expand Up @@ -32,7 +33,7 @@ export default class HttpRemote implements Remote
const options = { method: 'GET' };

const response = await this.#callRemote(remoteUrl, options);
const type = response.headers.get('Content-Type') || 'application/octet-stream';
const type = response.headers.get(HeaderKeys.CONTENT_TYPE) ?? HeaderValues.APPLICATION_STREAM;
const result = await response.arrayBuffer();
const content = Buffer.from(result);

Expand Down Expand Up @@ -68,7 +69,7 @@ export default class HttpRemote implements Remote
const options =
{
method: 'POST',
headers: { 'Content-Type': APPLICATION_JSON },
headers: { 'Content-Type': HeaderValues.APPLICATION_JSON },
body: JSON.stringify(body)
};

Expand All @@ -77,7 +78,7 @@ export default class HttpRemote implements Remote

async run(request: Request): Promise<ResultResponse>
{
request.setHeader('Content-Type', APPLICATION_JSON);
request.setHeader(HeaderKeys.CONTENT_TYPE, HeaderValues.APPLICATION_JSON);

const versionString = request.version.toString();
const argsObject = Object.fromEntries(request.args);
Expand Down Expand Up @@ -128,7 +129,8 @@ export default class HttpRemote implements Remote

async #getResponseResult(response: Response): Promise<unknown>
{
const contentType = response.headers.get('X-Jitar-Content-Type');
const contentType = response.headers.get(HeaderKeys.JITAR_CONTENT_TYPE)
?? response.headers.get(HeaderKeys.CONTENT_TYPE);

if (contentType?.includes('undefined'))
{
Expand Down
54 changes: 40 additions & 14 deletions packages/http/src/HttpServer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,14 +3,17 @@ import express, { Express, Request, Response, NextFunction } from 'express';
import { Server as Http } from 'http';

import { RunModes } from '@jitar/execution';
import type { Server, ServerResponse } from '@jitar/runtime';
import { Server, ServerResponse, ContentTypes } from '@jitar/runtime';
import { Validator } from '@jitar/validation';

import HeaderKeys from './definitions/HeaderKeys';
import IgnoredHeaderKeys from './definitions/IgnoredHeaderKeys';
import HeaderValues from './definitions/HeaderValues';

const DEFAULT_PORT = '3000';
const DEFAULT_BODY_LIMIT = 1024 * 200; // 200 KB

const IGNORED_QUERY_PARAMETERS = ['version'];
const IGNORED_HEADER_KEYS = ['host', 'connection', 'content-length', 'accept-encoding', 'user-agent', 'keep-alive'];
const IGNORED_QUERY_PARAMETERS = ['version']; // TODO: Refactor version to custom header

export default class HttpServer
{
Expand Down Expand Up @@ -51,7 +54,7 @@ export default class HttpServer
this.#app.use(express.urlencoded({ extended: true }));
this.#app.use(this.#addDefaultHeaders.bind(this));

this.#app.disable('x-powered-by');
this.#app.disable(HeaderKeys.POWERED_BY);
}

#setupRoutes(): void
Expand Down Expand Up @@ -96,7 +99,7 @@ export default class HttpServer
// eslint-disable-next-line @typescript-eslint/no-unused-vars
#addDefaultHeaders(request: Request, response: Response, next: NextFunction): void
{
response.setHeader('X-Content-Type-Options', 'nosniff');
response.setHeader(HeaderKeys.CONTENT_TYPE_OPTIONS, HeaderValues.NO_SNIFF);

next();
}
Expand Down Expand Up @@ -252,7 +255,7 @@ export default class HttpServer
const lowerKey = key.toLowerCase();
const stringValue = value.toString();

if (IGNORED_HEADER_KEYS.includes(lowerKey))
if (IgnoredHeaderKeys.includes(lowerKey))
{
continue;
}
Expand All @@ -266,10 +269,11 @@ export default class HttpServer
#transformResponse(response: Response, serverResponse: ServerResponse): Response
{
const status = this.#transformStatus(serverResponse);
const contentType = this.#transformContentType(serverResponse);

response.status(status);
response.setHeader('Content-Type', serverResponse.contentType);
response.setHeader('X-Jitar-Content-Type', serverResponse.contentType);
response.setHeader(HeaderKeys.CONTENT_TYPE, contentType);
response.setHeader(HeaderKeys.JITAR_CONTENT_TYPE, serverResponse.contentType);

for (const [name, value] of Object.entries(serverResponse.headers))
{
Expand All @@ -291,14 +295,36 @@ export default class HttpServer
return serverResponse.status;
}

#transformContentType(serverResponse: ServerResponse): string
{
const contentType = serverResponse.contentType.toLowerCase();

switch (contentType)
{
case ContentTypes.BOOLEAN:
case ContentTypes.NUMBER:
case ContentTypes.UNDEFINED:
case ContentTypes.NULL:
return ContentTypes.TEXT;
}

return contentType;
}

#transformResult(serverResponse: ServerResponse): unknown
{
if (typeof serverResponse.result === 'number'
|| typeof serverResponse.result === 'boolean')
{
return String(serverResponse.result);
}
const result = serverResponse.result;

// if (result === undefined || result === null)
// {
// return '';
// }

if (typeof result === 'number' || typeof result === 'boolean')
{
return String(result);
}

return serverResponse.result;
return result;
}
}
11 changes: 11 additions & 0 deletions packages/http/src/definitions/HeaderKeys.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@

const HeaderKeys =
{
CONTENT_TYPE: 'Content-Type',
CONTENT_LENGTH: 'Content-Length',
CONTENT_TYPE_OPTIONS: 'X-Content-Type-Options',
JITAR_CONTENT_TYPE: 'X-Jitar-Content-Type',
POWERED_BY: 'X-Powered-By'
} as const;

export default HeaderKeys;
9 changes: 9 additions & 0 deletions packages/http/src/definitions/HeaderValues.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@

const HeaderValues =
{
NO_SNIFF: 'nosniff',
APPLICATION_JSON: 'application/json',
APPLICATION_STREAM: 'application/octet-stream'
} as const;

export default HeaderValues;
4 changes: 4 additions & 0 deletions packages/http/src/definitions/IgnoredHeaderKeys.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@

const IgnoredHeaderKeys: string[] = ['host', 'connection', 'content-length', 'accept-encoding', 'user-agent', 'keep-alive'] as const;

export default IgnoredHeaderKeys;
1 change: 1 addition & 0 deletions packages/runtime/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
export { default as Client } from './client/Client';
export { default as ClientBuilder } from './client/ClientBuilder';

export { default as ContentTypes } from './server/definitions/ContentTypes';
export { default as ServerResponse } from './server/types/ServerResponse';
export { default as Server } from './server/Server';
export { default as ServerBuilder } from './server/ServerBuilder';

0 comments on commit dfd0037

Please sign in to comment.