///
import h = require('./Headers');
import utils = require('../Utils');
import log = require('../Log');
import context = require('../Context');
export class Response extends h.Headers {
static boundarySeparator = '--';
static headerSeparator = ':';
static bodySeparator = '\n\n';
public data:any;
public json:any;
public responses:Response[];
public error:Error;
public status:number;
public statusText:string;
public body:any;
private log:log.Log;
constructor(context:context.Context, status:number, statusText:string, body:any, headers?:any) {
super(context);
this.log = log.$get(context);
if (typeof(body) === 'string') {
body = body.replace(/\r/g, '');
if (!headers) {
var tmp = body.split(Response.bodySeparator);
headers = (tmp.length > 1) ? tmp.shift() : {};
body = tmp.join(Response.bodySeparator);
}
}
/** @type {Response[]|object} */
this.data = null;
/** @type {object} */
this.json = null;
/** @type {Response[]} */
this.responses = [];
/** @type {Error} */
this.error = null;
//@see http://stackoverflow.com/questions/10046972/msie-returns-status-code-of-1223-for-ajax-request
if (status == 1223) status = 204;
this.status = status;
this.statusText = statusText;
this.body = body;
try {
// Step 1. Parse headers
if (typeof(headers) === 'string') {
(headers || '')
.split('\n')
.forEach((header:string) => {
if (!header) return;
var parts = header.split(Response.headerSeparator),
name = parts.shift().trim();
this.setHeader(name, parts.join(Response.headerSeparator).trim());
});
} else {
this.setHeaders(headers);
}
// Step 1.1. JEDI proxy sometimes may omit Content-Type header
if (!this.hasHeader(h.Headers.contentType)) this.setHeader(h.Headers.contentType, h.Headers.jsonContentType);
// Step 2. Parse body
if (this.isJson() && !!this.body && typeof(this.body) === 'string') { // Handle 204 No Content -- response may be empty
this.json = JSON.parse(this.body);
this.data = this.json; // backwards compatibility
if (!this.checkStatus()) this.error = new Error(this.getError());
} else if (this.isMultipart()) { // Handle 207 Multi-Status
// Step 2.1. Split multipart response
var boundary = this.getContentType().match(/boundary=([^;]+)/i)[1],
parts = this.body.split(Response.boundarySeparator + boundary);
if (parts[0].trim() === '') parts.shift();
if (parts[parts.length - 1].trim() == Response.boundarySeparator) parts.pop();
// Step 2.2. Parse status info
var statusInfo = new Response(this.context, this.status, '', parts.shift());
// Step 2.3. Parse all other parts
this.responses = parts.map((part:string, i) => {
var status = statusInfo.data.response[i].status;
return new Response(this.context, status, '', part);
});
this.data = this.responses; // backwards compatibility
} else { //TODO Add more parsers
this.data = this.body;
}
} catch (e) { // Capture parse errors
this.log.error('Response.parseResponse(): Unable to parse data');
this.log.error(e.stack || e);
this.log.error(this.body);
this.error = e;
}
}
/**
* @returns {boolean}
*/
isUnauthorized() {
return (this.status == 401);
}
checkStatus() {
return this.status >= 200 && this.status < 300;
}
getError() {
return this.data.message ||
this.data.error_description ||
this.data.description ||
'Unknown error';
}
}
export function $get(context:context.Context, status:number, statusText:string, body:any, headers?:any):Response {
return new Response(context, status, statusText, body, headers);
}