梦想 - 为OCAML和Initionalml的整洁Web框架

2021-04-10 11:45:52

梦想建立在五种类型。前两个是梦想的数据类型:

处理程序是从请求到响应的异步功能。示例1-hello显示了最简单的处理程序,我们传递给Dream.Run的匿名函数。这会创建一个完整的Web服务器!您还可以看到示例R-Hello的原因版本。

跨边是拍摄处理程序的函数,并在生成“更大”处理程序之前或之后运行一些代码。示例2-中间件将Dream.Logger中间件插入Web应用程序:

路由告诉Dream.Router哪个处理程序为每个请求选择。请参阅路由和示例3路由器。路由由vertm.get和Dream.Scope等助手创建:

'消息,发音为“任何消息”,允许某些功能将请求或响应作为参数,因为两者都在&#39中定义;消息。例如,在标题中:

分别为请求和响应的消息类型参数。除了彼此不同之外,这些没有意义。梦想只创建了传入的消息和传出消息。在文档中再也没有提到了传入和传出。

类型方法_ = [| “得到” “帖子” “放” `删除| `head | `connect | `选项| `踪影| `补丁| “字符串方法”

评估给定方法的字符串表示。例如,“Get被转换为&”&“"获得"

比较两种方法,即使一个表示为串,也检测到等于的方法。例如,

信息(1xx)状态代码。请参阅RFC7231§6.2和MDN。 101交换协议由Dream.WebSocket内部生成。通常没有必要直接使用它。

类型成功= [| `好的| `创造| `接受| `non_authoritative_information | `no_content | `reset_content | `partial_content]

成功(2xx)状态代码。请参阅RFC7231§6.3,RFC7233§4.1和MDN。最常见的是200 OK。

类型重定向= [| `multiply_choices | `moved_permanelath | `发现| `see_other |. `not_modified | `temporary_redirect | “永久”

重定向(3xx)状态代码。请参阅RFC7231§6.4和RFC7538§3和MDN。使用303参见另一种直接客户随访,特别是在提交表单后。使用301永久移动以进行永久重定向。

type client_error = [| `bad_request | `未经授权| “付款_一牌子| `禁止| `not_found | `method_not_allowed | `not_cceptable | `proxy_authentication_required | `request_timeout | `冲突| “走了” `lengege_required | `prevondition_failed | `payload_too_large | `uri_too_long | `unsupported_media_type | `Range_not_satisfiable | `期望_打开`misdireded_request | `太沉着| `upgrade_required | `prevondition_required | `too_many_requests | `request_header_fields_too_large | “unavailable_for_legal_reasons”]

客户端错误(4xx)状态代码。最常见的是400个糟糕请求,401未经授权,403禁止,当然,404未找到。

RFC 6585需要428个前提条件,429个要求太多,431请求标头太大。

键入server_error = [| `internal_server_error | `not_implemented | `bad_gateway | `service_unavailable |. `gateway_timeout | “http_version_not_supported”

服务器错误(5xx)状态代码。请参阅RFC7231§6.6和MDN。其中最常见的是500个内部服务器错误。

状态代码,包括直接表示为整数的代码。请参阅上面的完整列表和引用类型。

评估给定状态的字符串表示。例如,`not_found和`status 404都转换为"找不到"数字用于未知状态代码。例如,`状态567被转换为" 567"

将已知状态代码转换为它们的字符串表示表示。 对于未知状态代码,请评估无。 如果给定的状态为类型梦想,则评估为true。文件或在范围`状态100 - `状态199。 比较两个状态码,即使一个代码表示为数字,也会检测到等于代码。 例如, 将表示为VARIANTS表示为数字的状态代码。 梦想生成的状态代码始终是标准化的。 val回复:?状态:状态 - > ?代码:int - > ?标题:(字符串*字符串)列表 - > 弦 - > 回复 使用给定字符串创建一个新的响应。 〜代码和〜状态是指定状态代码的两种方法,默认情况下为200确定。 默认情况下,标题为空。 val回应:?状态:状态 - > ?代码:int - > ?标题:(字符串*字符串)列表 - > 弦 - > 响应承诺

val流:?状态:状态 - > ?代码:int - > ?标题:(字符串*字符串)列表 - > (响应 - >单位承诺) - >响应承诺

与梦想相同。响应,但调用deame.with_stream在内部准备流编写的响应,然后异步运行回调以执行它。请参见示例J-Stream。

有趣的要求 - > Demon.Stream(有趣的回复 - >让%lwt()= dream.write" foo" revall.close_stream响应中的回复。

具有给定名称的第一个标题。标题名称不区分大小写。请参阅RFC7230§3.2和MDN。

附加带给定名称和值的标题。不删除具有相同名称的任何现有标题。

Dream.set_cookie和Dream.Cookie专为圆形绊倒的安全饼干而设计。适用于当前服务器的最安全设置是自动推断出来的。请参见示例c-cookie。

梦想.Cookie Call评估某些" foo"但是交换的实际cookie可能看起来像:

dream.set_cookie具有大量可选参数,用于调整推断的安全设置。如果您使用它们,请传递与Dream.Cookie相同的参数自动撤消结果。

val set_cookie:?前缀:[`主机| “安全”选项 - > ?加密:BOOL - > ?到期:float - > ?max_age:float - > ?域名:String - > ?路径:字符串选项 - > ?安全:BOOL - > ?http_only:bool - > ?同样:[`严格| `lax | “无”选项 - >弦 - >弦 - >请求 - >响应 - >回复

追加Set-cookie:标题到响应。 infers从请求中获得最安全的默认值。

指定Dream.Run参数〜秘密,或者Web应用程序将无法从先前开始解密cookie。

大多数可选参数用于覆盖推断默认值。 〜到期并〜max_age独立有用。特别是删除cookie,使用〜到期:0。

〜prefix设置__host-,__secure或没有前缀,从最安全到最少。符合客户的客户端将拒绝接受cookie if〜域,〜路径和〜安全Don' t匹配前缀所暗示的约束。默认情况下,Devel.Set_Cookie根据其他设置和请求选择最严格的前缀。请参阅RFC6265BIS§4.1.3和MDN。

〜加密:false禁用cookie加密。在这种情况下,您必须确保cookie值不包含=,;或newlines。最简单的方法是通过梦想等编码器传递价值.to_base64url。看到梦想.Run参数〜秘密。

〜过期设置expires =属性。 该值与Unix.gettimeofday兼容。 请参阅RFC6265BIS§4.1.2.1和MDN。 〜PATH设置PATH =属性。 默认情况下,path =设置到请求中的站点前缀,通常/。 请参阅RFC6265BIS§4.1.2.4和MDN。 〜安全设置安全属性。 默认情况下,如果Dream.https为请求,则设置安全。 请参阅RFC6265BIS§4.1.2.5和MDN。 〜http_only设置HttpOnly属性。 httponly默认设置。 请参阅RFC6265BIS§4.1.2.6和MDN。 〜same_site设置samesite =属性。 默认情况下,Samesite设置为严格。 请参阅RFC6265BIS§4.1.2.7和MDN。 dream.te_set_cookie是此函数的“原始”版本,不做任何推断。 Val cookie:?前缀:[`主机| “安全”选项 - > ?解密:BOOL - > ?域名:String - > ?路径:字符串选项 - > ?安全:BOOL - > 弦 - > 请求 - > 字符串选项

传递与dream.set_cookie相同的可选参数,对于同一个cookie。这将允许Dream.Cookie推断cookie名称前缀,实现透明cookie往返,其中包含最安全的属性。

检索整个身体。存储参考,所以梦想。可以很多次使用。请参见示例6-echo。

检索身体块。块没有缓冲,因此只能读一次。请参见示例J-Stream。

使响应准备用梦想写作.write。您应该尽快从您的处理程序返回它 - 在梦中只有一次呼叫.WRITE之前将被接受。看到梦想。为了更方便的包装器。

流出字符串。当响应可以接受更多写入时,履行承诺。

C堆中的字节阵列。见BigArray.Array1。此类也在梦中安装的几个库中找到,因此它们的功能可以与Dream.Bigstring一起使用:

val下一个:大字节:(大字段 - > int - > int - >单位) - >关闭:(单位 - >单位) - > exn :( exn - >单位) - >请求 - >单元

梦想现在推荐使用yojson。另请参见PPX_YOJSON_CONV用于为OCAML数据类型生成JSON解析器和Serializers。

实现具有标准标题CSRF防御技术的OWASP验证源,这足以实现基本使用。如果仅依赖于Dream.origin_Referer_check,请不要允许`get或`head请求触发重要的副作用。

有关更全面的保护,请使用Dream.CSRF_Token生成CSRF令牌,向客户端发送给客户端(例如,在< eva>单页应用程序的标签中),并在x-csrf-token:header中存在。

dream.form_tag和梦想.Form往返安全形式。 DemaN.Form_Tag在模板内使用,以生成带有CSRF令牌的表单标题:

匹配%lwt dream.form请求| “好”["我.Field",价值] - > (* ... *)| _ - >梦。响应`bad_request.

类型' form_result = [| `好的' a | `已过期' a * float | `&#39的错误_ssession; a | `Invalid_token的' a | `sisce_token' a | `many_tokens' a | `fall_content_type]

根据最小到最严重的顺序形成CSRF检查结果。请参阅DemaN.Form和示例D形式。

剩下的构造函数,`Invalid_Token,`Missing_Token,`Word_Content_type)对应于错误,可疑活动或代币,因为解密密钥已在服务器上旋转。

将请求身体视为表单。执行CSRF检查。在模板中使用dream.form_tag透明生成将通过这些检查的表单。请参阅模板和示例D形式。

必须在会话中间件下进行呼叫,因为每个CSRF令牌都被选为会话。请参阅会话。

匹配%lwt dream.form请求| `好的["电子邮件",电子邮件; "姓名",名称] - > (* ... *)| _ - >梦..空白的`bad_request

匹配%lwt dream.form请求| `好的["电子邮件",电子邮件; "姓名",名称] - > (* ... *)| `已过期["电子邮件",电子邮件; "姓名",名称] - > (* ... *)| _ - >梦..空白的`bad_request

建议不要突变状态或在“已过期”和“错误”中发送敏感数据,因为它们可能表示对客户的攻击。

其余的案例,包括意外的字段集和demale.form_result的剩余构造函数,通常表示错误或攻击。它通常很好地用400个糟糕的要求回应所有这些。

类型零件= [| `files(string * string)列表| “弦值”] 然后通过Dream.Multipart与字段名配对配对,制作(字符串*零件)列表。 例如,如果表单具有<输入名称=" foo" type ="文件" 多个>,用户选择多个文件,所接收的字段名称和部分将是 像Demal.Form,还读取文件,内容类型:必须是多级/表单数据。 <形式> 可以在模板中生成标记和CSRF令牌 Dream.Multipart将整个文件读入内存中,因此它仅适用于原型设计,或者使用尚未添加的文件大小和计数限制。 请参阅Dream.Upload以用于流式传输版本。 键入upload_event = [| `string * string的文件| `字符串*字符串| `做完了 `fall_content_type] `file(field_name,filename)开始流中的文件。 Web应用程序应该调用deame.upload_file,直到无,然后调用dream.upload再次。

不验证CSRF令牌。有几种方法可以为上传流添加CSRF保护,包括:

使用dream.form_tag生成表单。在上传和调用dream.verify_csrf_token期间检查`字段(" dream.csrf",令牌)。

在客户端中使用formdata通过ajax提交多部分/表单数据,并包含自定义标题。

表单标记生成器Devel.Form_Tag生成并插入梦想的CSRF令牌.Form和Dream.MultiPart透明验证。

`已过期和`错误_session分别在正常使用情况下,当用户' s形式或会话到期时。但是,它们还可以指示攻击,包括被盗令牌,从其他会话中被盗令牌,或尝试在登录后尝试使用无效的前会话中的令牌。

`无效表示具有糟糕签名的令牌,梦中未生成的有效负载,或通常不能由普通用户触发的其他严重错误。 `无效通常对应于错误或攻击。在服务器上不再使用旧密钥后,也可以在非常旧的令牌中出现无效。

返回绑定到给定请求的新鲜CSRF令牌,并与梦想的秘密签名.Run。 〜vigw_for是令牌' s寿命,在几秒钟内。默认值为一小时(3600.)。梦想使用不存储服务器端的签名令牌。

梦想包括模板预处理器,允许在同一文件中交织OCAML和HTML: 隐含地在以<的一行上 并由至少一列缩进。 该行是模板的一部分。 在以%%开头的行之后明确。 %%行不是模板的一部分。 %%行也可用于设置模板选项。 目前唯一支持的选项是使用Devel.Write将模板流式传输到范围内的响应的%%响应。 这在示例W-Thate-Stream-Stream和R模板流中示出。 &lt%s代码%> 预计代码要评估为字符串,并将字符串插入模板。 在第一列中以%开头的行是模板内的OCAML代码。 它的值未插入模板。 实际上,它可以是控制流动构建体的碎片。 <%代码%> 是一个%的含量,可用于模板线内的短片段。

s中的s中的s中%>实际上是一种PrintF样式格式规范。因此,例如,可以使用&lt%02x代码%&gt来打印两个十六进制数字。

&lt%s代码%>使用dream.html_escape自动转义代码的结果。这可以抑制! &lt%s!代码%>字面上打印代码结果。 Dream.html_escape只是在HTML文本和引用的属性值中使用的安全。它在< style&gt中没有提供XSS保护。标签或< script&gt中的字格javascript;标签。

预处理器将输出原因代码,如果模板源文件' s扩展是.re,例如template.eml.re。请参阅示例R-Template和R-Them Straft。

生成一个<形式>标签和<输入>标记与CSRF令牌,适合与Dream.Form和Dream.Multipart一起使用。例如,在模板中,

根据它们的位置,涉及这些文档的各个部分,散落的有趣内置的中间摆力。此部分仅包含通用中间件组合器。

创建路由器。除了解释路由外,路由器是一个中间件,如果其路由符合请求,则调用其下一个处理程序。路由组件从:是参数,可以通过dream.param检索.Param。请参见示例3路由器。

让()= dream.run @@ dream.router [dream.get" / echo /:word" @@有趣的请求 - > dream.respond(dream.param" word"请求); ] @@ dream.not_found.

Dream.Scope是现场组成的主要形式。但是,梦想也支持与*的完整子部分:

让()= dream.run @@ dream.router [dream.get" / static / *" @@ dream.static" www / static&#34 ;; ] @@ dream.not_found.

*导致请求'由路由前缀修剪的路径,以及请求' s前缀要由它扩展。它主要有助于“安装”梦幻般的梦想。

它也可以用作逃生舱口,以转换处理器,该处理程序可以包括其自己的路由器,进入子站点。但是,最好撰写带有路由和梦想的网站.Scope而不是不透明的处理程序和*,因为,在将来,可以查询站点结构元数据的路由。

检索路径参数。如果缺少,Dream.Param提出了一个例外 - 程序是错误的。

小组在公共路径前缀和跨方下路由。只有在路线匹配匹配时才会运行中间字。

让()= dream.run @@ dream.router {dream.get" / static / *" @@ dream.static" www / static&#34 ;; } @@ dream.not_found.

Dream.static local_path检查请求路径是相对的,不包含父目录引用。然后调用〜handler local_root路径请求。默认处理程序在文件系统中的local_root / path中的文件响应,如果文件不存在,则找不到404。它使用Magic-Mime来设置内容类型:

pass〜处理程序实现任何其他行为,包括从内存中服务文件。 〜处理程序可以在其响应中设置标题,包括ETAG:

Dream' s默认会话包含用于应用程序数据的字符串到字符串字典。例如,可以具有登录的会话

通过会话中间件的所有请求都分配了一个会话,现有的一个或一个新的空话,称为前会话。

突变请求中的值' s会话。后端可以立即提交存储值,因此此功能返回承诺。

存储服务器内存中的会话。将会话键传递给Cookie中的客户端。服务器流程退出时会话数据丢失。

在加密cookie中存储会话。 pass dream.run〜秘密能够从以前的服务器运行解密cookie。

存储SQL数据库中的会话。将会话键传递给Cookie中的客户端。必须在dream.sql_pool下使用。期待一个表格

create table dream_session(关键文字不是null主键,ID文本不是null,Expires_at Real Not Null,有效载荷文本不是null)

创建一个新的101个切换协议响应。一旦此响应返回到Dream' S HTTP层,回调将传递一个新的WebSocket,并且应用程序可以开始使用它。请参见示例K-WebSocket。

让my_handler =有趣的请求 - >梦想.Websocket(有趣的Websocket - > let%lwt()= dream.send"你好,世界!" websocket在dream.close_websocket websocket);

val发送:?种类:[`文本| “二元” - >弦 - > WebSocket - >单位承诺

有〜种:`文本,默认值,消息被解释为UTF-8字符串。客户端将收到它将其转码到JavaScript' s utf-16表示。

有〜种:“二进制”,将无法修改的消息,作为BLOB或ArrayBuffer。看到mdn,

......