♻ Extract response handler

This commit is contained in:
C-3PO 2018-07-04 19:51:20 +02:00
parent e4c2754493
commit c821327a6e
Signed by: c3po
GPG key ID: 62993C4BB4D86F24
4 changed files with 59 additions and 33 deletions

View file

@ -0,0 +1,48 @@
import * as http from 'http';
/** Too avoid */
const MAX_MEMORY_SIZE = 100 * 1024 * 1024;
export default function handleResponse(
resolve: (value: ArrayBuffer) => void,
reject: (reason: string) => void,
response: http.IncomingMessage,
) {
//Check that file exists (200 HTTP status code)
if (response.statusCode !== 200) {
return reject(`Expected status code 200 but received ${response.statusCode}`);
}
//Check file size
const headerLength = Number(response.headers['content-length']);
if (headerLength > MAX_MEMORY_SIZE) {
return reject('File size too large to be handled in memory.');
}
//If we receive a part of the response, store it
const chunkList: Buffer[] = [];
let totalLength = 0;
response.on('data', (chunk: Buffer) => {
totalLength += chunk.length;
//Exit early if we received too much data
if (totalLength > headerLength) {
return reject(`Expected length ${headerLength} but received at least ${totalLength}`);
}
//Add chunk to array
chunkList.push(chunk);
});
//If we finished reading response, check for correctness and return it
response.on('end', () => {
//Check that length is correct
if (totalLength !== headerLength) {
return reject(`Expected length ${headerLength} but received ${totalLength}`);
}
//Return file contents as ArrayBuffer
const fileContents = Buffer.concat(chunkList, totalLength);
return resolve(fileContents.buffer as ArrayBuffer);
});
}

View file

@ -1,4 +1,4 @@
/* --- DNS resolver for the CDN storing SWTOR's patch files ---
/* --- DNS resolver for the CDN storing SWTORs patch files ---
|
| The SWTOR launcher first connects to cdn-patch.swtor.com,
| there the traffic is split onto Akamai and Level3, and
@ -28,7 +28,7 @@
import { exec} from 'child_process';
import * as dns from 'dns';
import { IDnsResult } from '../interfaces/IDnsResult';
import { IDnsResult } from '../../interfaces/IDnsResult';
//TODO: send e-mail with the error
const assert = (cond: boolean) => { if (!cond) { console.warn('Assert failed'); } };
@ -39,7 +39,7 @@ async function resolveDns(domain: string): Promise<IDnsResult[]> {
//check given string for correctness to prevent injection attacks
if (!domain.match(/^[a-z0-9]+([-.]{1}[a-z0-9]+)*\.[a-z]{2,3}$/)) { return resolve([]); }
//Check Level3/North_America separetely
//Check Level3/North_America separately
if (domain !== 'cdn-patch.swtor.com') {
dns.resolve4(domain, { ttl: true }, (err, result) => {
return resolve(result.map(({ address, ttl }) => ({ address, ttl, type: 'level3-us' as IDnsResult['type'] })));

View file

@ -1,41 +1,19 @@
import * as http from 'http';
import handleResponse from './funcs/handleResponse';
const MAX_MEMORY_SIZE = 100 * 1024 * 1024;
/** Downloads the given URL into memory and returns it as an ArrayBuffer. Throws error if download fails or file is too large to be handled in memory. */
export default function getUrlContents({ host, path }: {host: string, path: string}): Promise<ArrayBuffer> {
return new Promise((resolve, reject) => {
const request = http.request({
family: 4,
host,
path,
}, (response) => {
if (response.statusCode !== 200) {
return reject(`Expected status code 200 but received ${response.statusCode}`);
}
const headerLength = Number(response.headers['content-length']);
if (headerLength > MAX_MEMORY_SIZE) {
reject('File size too large to be handled in memory.');
}, handleResponse.bind(null, resolve, (reason: string) => { request.abort(); reject(reason); }));
//In case of connection errors, exit early
request.on('error', (error) => {
request.abort();
return;
}
const chunkList: Buffer[] = [];
let totalLength = 0;
response.on('data', (chunk: Buffer) => {
chunkList.push(chunk);
totalLength += chunk.length;
});
response.on('end', () => {
if (totalLength !== headerLength) {
return reject(`Expected length ${headerLength} but received ${totalLength}`);
}
const fileContents = Buffer.concat(chunkList, totalLength);
resolve(fileContents.buffer as ArrayBuffer);
});
});
request.on('error', (e) => {
reject(e);
return reject(error);
});
request.end();
});

View file

@ -1,5 +1,5 @@
import { IServerEntry } from '../interfaces/IDnsResult';
import resolveDns from './resolveDns';
import resolveDns from './funcs/resolveDns';
/** Time when this script started, for delta time calculations */
const startTime = Date.now();