@leansdk/leanrc
Version:
LeanRC is a MVC framework for creating graceful applications
299 lines (252 loc) • 9.19 kB
text/coffeescript
# This file is part of LeanRC.
#
# LeanRC is free software: you can redistribute it and/or modify
# it under the terms of the GNU Lesser General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# LeanRC is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU Lesser General Public License for more details.
#
# You should have received a copy of the GNU Lesser General Public License
# along with LeanRC. If not, see <https://www.gnu.org/licenses/>.
# net = require 'net' # will be used only 'isIP' function
# contentType = require 'content-type'
# stringify = require('url').format
# parse = require 'parseurl'
# qs = require 'querystring'
# typeis = require 'type-is'
# fresh = require 'fresh'
###
Идеи взяты из https://github.com/koajs/koa/blob/master/lib/request.js
###
module.exports = (Module)->
{
AnyT, NilT
FuncG, UnionG, MaybeG
RequestInterface, SwitchInterface, ContextInterface
CoreObject
Utils: { _ }
} = Module::
class Request extends CoreObject
RequestInterface
Module
req: Object, # native request object
get: -> .req
switch: SwitchInterface,
get: -> .switch
ctx: ContextInterface
# baseUrl: String # под вопросом?
# database: String # возможно это тоже надо получать из метода из отдельного модуля
# pathname: String
# pathParams: Object # вынести в отдельный модуль, который будет подключаться как миксин, а в чейнинге будет вызваться метод, который будет распарсивать парамсы
# cookie: Function,
# default: (name, options)->
body: MaybeG AnyT # тело должен предоставлять миксин из отдельного модуля
header: Object,
get: ->
headers: Object,
get: -> .headers
originalUrl: String,
get: -> .originalUrl
url: String,
get: -> .url
set: (url)-> .url = url
origin: String,
get: -> "#{@protocol}://#{@host}"
href: String,
get: ->
return if /^https?:\/\//i.test @originalUrl
return +
method: String,
get: -> .method
set: (method)-> .method = method
path: String,
get: ->
parse = require 'parseurl'
parse().pathname
set: (path)->
parse = require 'parseurl'
url = parse
return if url.pathname is path
url.pathname = path
url.path = null
stringify = require('url').format
= stringify url
query: Object,
get: ->
qs = require 'querystring'
qs.parse
set: (obj)->
qs = require 'querystring'
= qs.stringify obj
obj
querystring: String,
get: ->
return '' unless ?
parse = require 'parseurl'
parse().query ? ''
set: (str)->
parse = require 'parseurl'
url = parse
return if url.search is "?#{str}"
url.search = str
url.path = null
stringify = require('url').format
= stringify url
search: String,
get: ->
return '' unless
"?#{@querystring}"
set: (str)-> = str
host: String,
get: ->
{trustProxy} = .switch.configs
host = trustProxy and 'X-Forwarded-Host'
host = host or 'Host'
return '' unless host
host.split(/\s*,\s*/)[0]
# port отсутствует в интерфейсе koa - возможно лучше его и здесь не делать, чтобы не ломать интерфейс koa
# port: Number,
# get: ->
# host =
# port = if host
# host.split(':')[1]
# unless port
# port = if is 'https'
# 443
# else
# 80
# Number port
hostname: String,
get: ->
host =
return '' unless host
host.split(':')[0]
fresh: Boolean,
get: ->
method =
s = .status
# GET or HEAD for weak freshness validation only
if 'GET' isnt method and 'HEAD' isnt method
return no
# 2xx or 304 as per rfc2616 14.26
if (s >= 200 and s < 300) or 304 is s
fresh = require 'fresh'
return fresh , .response.headers
return no
stale: Boolean,
get: -> not
idempotent: Boolean,
get: ->
methods = ['GET', 'HEAD', 'PUT', 'DELETE', 'OPTIONS', 'TRACE']
_.includes methods,
socket: MaybeG(Object),
get: -> .socket
charset: String,
get: ->
type = 'Content-Type'
return '' unless type?
try
contentType = require 'content-type'
type = contentType.parse type
catch err
return ''
type.parameters.charset ? ''
length: Number,
get: ->
if (contentLength = 'Content-Length')?
return 0 if contentLength is ''
~~Number contentLength
else
0
protocol: String,
get: ->
{trustProxy} = .switch.configs
if ?.encrypted
return 'https'
if .secure
return 'https'
unless trustProxy
return 'http'
proto = 'X-Forwarded-Proto'
proto = 'http' unless proto
proto.split(/\s*,\s*/)[0]
# xhr отсутствует в интерфейсе koa - возможно лучше его и здесь не делать, чтобы не ломать интерфейс koa
# xhr: Boolean,
# get: ->
# 'xmlhttprequest' is String(['X-Requested-With']).toLowerCase()
secure: Boolean,
get: -> is 'https'
ip: String
ips: Array,
get: ->
{trustProxy} = .switch.configs
value = 'X-Forwarded-For'
if trustProxy and value
value.split /\s*,\s*/
else
[]
subdomains: Array,
get: ->
{subdomainOffset:offset} = .switch.configs
hostname =
net = require 'net'
return [] if net.isIP(hostname) isnt 0
hostname
.split('.')
.reverse()
.slice offset ? 0
accepts: FuncG([MaybeG UnionG String, Array], UnionG String, Array, Boolean),
default: (args...)-> .accept.types args...
acceptsCharsets: FuncG([MaybeG UnionG String, Array], UnionG String, Array),
default: (args...)-> .accept.charsets args...
acceptsEncodings: FuncG([MaybeG UnionG String, Array], UnionG String, Array),
default: (args...)-> .accept.encodings args...
acceptsLanguages: FuncG([MaybeG UnionG String, Array], UnionG String, Array),
default: (args...)-> .accept.languages args...
'is': FuncG([UnionG String, Array], UnionG String, Boolean, NilT),
default: (args...)->
[types] = args
typeis = require 'type-is'
return typeis unless types
unless _.isArray types
types = args
typeis , types
type: String,
get: ->
type = 'Content-Type'
return '' unless type?
type.split(';')[0]
get: FuncG(String, String),
default: (field)-> #[name]
req =
switch field = field.toLowerCase()
when 'referer', 'referrer'
req.headers.referrer ? req.headers.referer ? ''
else
req.headers[field] ? ''
# inspect: FuncG([], Object),
# default: ->
# return unless
#
# toJSON: FuncG([], Object),
# default: -> _.pick @, ['method', 'url', 'header']
restoreObject: Function,
default: ->
throw new Error "restoreObject method not supported for #{@name}"
yield return
replicateObject: Function,
default: ->
throw new Error "replicateObject method not supported for #{@name}"
yield return
init: FuncG(ContextInterface),
default: (context)->
= context
= [0] ? .socket?.remoteAddress ? .remoteAddress ? ''
return