neft
Version:
Universal Platform
177 lines (146 loc) • 4.89 kB
text/coffeescript
'use strict'
zlib = require 'zlib'
log = require 'src/log'
utils = require 'src/utils'
path = require 'path'
Document = require 'src/document'
FormData = require 'form-data'
log = log.scope 'Networking'
HEADERS =
'Host': (obj) ->
host = ///^(?:[a-z]+):\/\/(.+?)(?:\/)?$///.exec(obj.networking.url)
if host then host[1] else obj.networking.url
'Cache-Control': 'no-cache'
'Content-Language': (obj) -> obj.networking.language
'X-Frame-Options': 'deny'
'Access-Control-Allow-Headers': 'x-cookies, x-expected-type'
'Access-Control-Expose-Headers': 'x-cookies, x-expected-type'
METHOD_HEADERS =
GET:
'Access-Control-Allow-Origin': (obj) ->
{networking} = obj
if networking.allowAllOrigins
'*'
else
obj.networking.url
'Allow': 'GET, POST, PUT, DELETE'
GZIP_ENCODING_HEADERS =
'Content-Encoding': 'gzip'
###
Set headers in the server response
###
setHeaders = (res, headers, ctx) ->
for name, value of headers
unless res.getHeader(name)?
if typeof value is 'function'
value = value ctx
res.setHeader name, value
return
###
Parse passed data into expected type
###
parsers =
'text': (data) ->
data + ''
'json': (data) ->
if data instanceof Error
data = utils.errorToObject data
try
JSON.stringify data
catch
data
'html': (data) ->
if data instanceof Document
data.node.stringify()
else
data
'binary': (data) ->
formData = new FormData
for key, val of data
formData.append key, val
formData
prepareData = (type, res, data) ->
# determine data type
switch type
when 'text'
mimeType = 'text/plain; charset=utf-8'
when 'json'
mimeType = 'application/json; charset=utf-8'
when 'html'
mimeType = 'text/html; charset=utf-8'
# parse data into expected type
parsedData = parsers[type](data)
if mimeType? and not res.getHeader('Content-Type')?
res.setHeader 'Content-Type', "#{mimeType}; charset=utf-8"
parsedData
###
Send data in server response
###
sendData = do ->
senders =
'text': do ->
send = (res, data) ->
if typeof data is 'string'
len = Buffer.byteLength data
else
len = data and data.length
if isFinite(len)
res.setHeader 'Content-Length', len
res.end data + ''
(req, res, data, callback) ->
acceptEncodingHeader = req?.headers['Accept-Encoding']
useGzip = acceptEncodingHeader and utils.has(acceptEncodingHeader, 'gzip')
unless useGzip
send res, data
return callback()
zlib.gzip data, (err, gzipData) ->
if err
send res, data
else
setHeaders res, GZIP_ENCODING_HEADERS
send res, gzipData
callback()
'binary': (req, res, data, callback) ->
# set headers
setHeaders res, data.getHeaders()
# get length
data.getLength (err, length) ->
if err
return callback err
res.setHeader 'Content-Length', length
data.pipe res
(type, req, res, data, callback) ->
sender = senders[type] or senders.text
sender req, res, data, callback
module.exports = (Networking, pending) ->
exports =
_prepareData: prepareData
_sendData: sendData
setHeader: (res, name, val) ->
if name? and val?
# get config obj
obj = pending[res.request.uid]
obj.serverRes.setHeader name, val
send: (res, data, callback) ->
# get config obj
obj = pending[res.request.uid]
return unless obj
delete pending[res.request.uid]
{serverReq, serverRes} = obj
# write headers
setHeaders serverRes, HEADERS, obj
if headers = METHOD_HEADERS[serverReq.method]
setHeaders serverRes, headers, obj
# set status
serverRes.statusCode = res.status
# cookies
if cookies = utils.tryFunction(JSON.stringify, null, [res.cookies], null)
serverRes.setHeader 'X-Cookies', cookies
# send data
{type} = res.request
data ?= ''
data = prepareData type, serverRes, data
sendData type, serverReq, serverRes, data, (err) ->
callback err
redirect: (res, status, uri, callback) ->
exports.send res, null, callback