You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
lib/src/http/lifecycle/Request.ts

133 lines
3.5 KiB

import {Injectable, ScopedContainer, Container} from "@extollo/di"
import {infer} from "@extollo/util"
import {IncomingMessage} from "http"
import {HTTPCookieJar} from "../kernel/HTTPCookieJar";
import {TLSSocket} from "tls";
import * as url from "url";
// FIXME - add others?
export type HTTPMethod = 'post' | 'get' | 'patch' | 'put' | 'delete' | 'unknown';
export function isHTTPMethod(what: any): what is HTTPMethod {
return ['post', 'get', 'patch', 'put', 'delete'].includes(what)
}
export interface HTTPProtocol {
string: string,
major: number,
minor: number,
}
export interface HTTPSourceAddress {
address: string;
family: 'IPv4' | 'IPv6';
port: number;
}
@Injectable()
export class Request extends ScopedContainer {
public readonly cookies: HTTPCookieJar;
public readonly url: string;
public readonly fullUrl: string;
public readonly method: HTTPMethod;
public readonly secure: boolean;
public readonly protocol: HTTPProtocol;
public readonly path: string;
public readonly rawQueryData: {[key: string]: string | string[] | undefined};
public readonly query: {[key: string]: any};
public readonly isXHR: boolean;
public readonly address: HTTPSourceAddress;
constructor(
protected clientRequest: IncomingMessage
) {
super(Container.getContainer())
this.secure = !!(clientRequest.connection as TLSSocket).encrypted
this.cookies = new HTTPCookieJar(this)
this.url = String(clientRequest.url)
this.fullUrl = (this.secure ? 'https' : 'http') + `://${this.getHeader('host')}${this.url}`
const method = clientRequest.method?.toLowerCase()
this.method = isHTTPMethod(method) ? method : 'unknown'
this.protocol = {
string: clientRequest.httpVersion,
major: clientRequest.httpVersionMajor,
minor: clientRequest.httpVersionMinor,
}
this.register(Request)
this.instances.push({
key: Request,
value: this,
})
const parts = url.parse(this.url, true)
this.path = parts.pathname ?? '/'
this.rawQueryData = parts.query
const query: {[key: string]: any} = {}
for ( const key in this.rawQueryData ) {
const value = this.rawQueryData[key]
if ( Array.isArray(value) ) {
query[key] = value.map(x => infer(x))
} else if ( value ) {
query[key] = infer(value)
} else {
query[key] = value
}
}
this.query = query
this.isXHR = String(this.clientRequest.headers['x-requested-with']).toLowerCase() === 'xmlhttprequest'
// @ts-ignore
const {address = '0.0.0.0', family = 'IPv4', port = 0} = this.clientRequest.connection.address()
this.address = {
address,
family,
port
}
}
public async prepare() {
}
public getHeader(name: string) {
return this.clientRequest.headers[name.toLowerCase()]
}
public toNative() {
return this.clientRequest
}
public input(key: string) {
if ( key in this.query ) {
return this.query[key]
}
}
// session
// route
// respond
// body
// hostname
/*
param
json
fresh/stale - cache
remote ips (proxy)
signedCookies
accepts content type, charsets, encodings, languages
is content type (wants)
range header parser
*/
}