/
httpHelper.js
146 lines (134 loc) · 4.21 KB
/
httpHelper.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
/**
* Copyright (c) 2011 Bruno Jouhier <bruno.jouhier@sage.com>
* MIT License
*/
"use strict";
if (!require('streamline/module')(module)) return;
console.log("streamline/lib/streams/server/httpHelper is OBSOLETE.\nYou can still turn it into a private module and hack it at your will.")
var urlHelper = require("streamline/lib/util/url");
/// !nodoc -- experimental
///
/// # streamline/lib/streams/server/httpHelper
///
/// HTTP helpers
exports.HttpStatus = {
OK: 200,
Created: 201,
Accepted: 202,
NoContent: 204,
MovedPermanently: 301,
Found: 302,
SeeOther: 303,
NotModified: 304,
TemporaryRedirect: 307,
BadRequest: 400,
Unauthorized: 401,
Forbidden: 403,
NotFound: 404,
MethodNotAllowed: 405,
NotAcceptable: 406,
Conflict: 409,
Gone: 410,
PreconditionFailed: 412,
UnsupportedMediaType: 415,
InternalServerError: 500,
NotImplemented: 501,
ServiceUnavailable: 503
}
function _classifyMedia(str) {
if (str == "*" || str == "*/*") return "*";
var lower = str.toLowerCase();
if (lower.indexOf("xml") >= 0) return "xml";
if (lower.indexOf("html") >= 0) return "html";
if (lower.indexOf("json") >= 0) return "json";
if (lower.indexOf("text") >= 0) return "text";
if (lower.indexOf("image") >= 0) return "image";
if (lower.indexOf("pdf") >= 0) return "pdf";
return "unknown";
}
exports.parseAccept = function(str) {
// parse and sort by decreasing quality
var accept = (str || "").toString().split(/,\s*/).map(function(part, i) {
var m = part.match(/^([^\s,]+?)(?:;\s*q=(\d+(?:\.\d+)?))?$/)
return m && [m[1], Number(m[2] || 1.0), i];
}).filter(function(elt) {
return elt;
}).sort(function(elt1, elt2) {
return elt2[1] - elt1[1] || elt1[2] - elt2[2]; // 2nd test to preserve order
}).map(function(elt) {
var split = elt[0].split(';');
var result = {
rawType: split[0],
type: _classifyMedia(split[0]),
parameters: {}
};
split.slice(1).forEach(function(str) {
var pair = str.split(/\s*=\s*/);
result.parameters[pair[0]] = pair[1];
});
return result;
})
// empty accept means accept anything
return accept.length > 0 ? accept : [{
rawType: "*",
type: "*",
parameters: {}
}];
}
function HttpError(statusCode, message) {
this.statusCode = statusCode;
this.message = message;
this.stack = new Error().stack;
}
exports.tracer = null;
exports.HttpContext = function(request, response, options) {
if (request == null) // subclassing
return;
options = options || {};
if (exports.tracer) {
exports.tracer("\nHTTP REQUEST: " + request.method + " " + request.url + "\n");
exports.tracer("headers: " + JSON.stringify(request.headers) + "\n");
}
this.request = request;
this.response = response;
this.method = (request.headers[options.methodHeader || "x-http-method-override"] || request.method).toLowerCase();
// URL stuff
var _split = request.url.split('?');
this.path = _split.splice(0, 1)[0];
var _urlBegin = (request.socket.secure ? "https" : "http") + "://" + request.headers.host;
this.url = _urlBegin + this.path;
this.rawQuery = _split.join('?');
this.query = urlHelper.parseQueryString(this.rawQuery);
var _segments = this.path.split('/').map(function(seg) {
return decodeURIComponent(seg);
});
var _segI = 1; // start after leading /
this.walkUrl = function() {
return _segments[_segI++];
}
this.walked = function() {
return _urlBegin + _segments.slice(0, _segI).join("/");
}
// Accept stuff
this.rawAccept = this.query[options.acceptParam] || request.headers.accept || "*";
this.accept = exports.parseAccept(this.rawAccept);
// Request body stuff
this.parseBody = function(_) {
var ct = request.headers["content-type"];
if (!ct) return null;
if (ct.indexOf("application/json") !== 0) throw new HttpError(415, "expected application/json, got: " + ct);
// assume utf8 -- be smarter later
//request.setEncoding('utf8');
var str = request.readAll(_);
if (str == null) return null;
if (exports.tracer) exports.tracer("body: " + str + "\n")
return JSON.parse(str);
}
this.reply = function(code, message, headers) {
headers = headers || {};
if (message && !headers["content-type"]) headers["content-type"] = "text/plain";
response.writeHead(code, headers);
response.end(message);
}
this.scratch = {}; // scratch area where business logic can write stuff
}