Browse Source

copy actix-web2

master
Nikolay Kim 2 years ago
parent
commit
2d7293aaf8
127 changed files with 7543 additions and 43470 deletions
  1. +2
    -830
      CHANGES.md
  2. +36
    -86
      Cargo.toml
  3. +0
    -16
      build.rs
  4. +54
    -0
      examples/basic.rs
  5. +0
    -3
      rustfmt.toml
  6. +648
    -0
      src/app.rs
  7. +169
    -263
      src/application.rs
  8. +74
    -0
      src/blocking.rs
  9. +0
    -391
      src/body.rs
  10. +0
    -1340
      src/client/connector.rs
  11. +0
    -120
      src/client/mod.rs
  12. +0
    -238
      src/client/parser.rs
  13. +0
    -553
      src/client/pipeline.rs
  14. +0
    -783
      src/client/request.rs
  15. +0
    -124
      src/client/response.rs
  16. +0
    -412
      src/client/writer.rs
  17. +0
    -294
      src/context.rs
  18. +0
    -455
      src/de.rs
  19. +0
    -1426
      src/error.rs
  20. +0
    -114
      src/extensions.rs
  21. +627
    -735
      src/extractor.rs
  22. +327
    -0
      src/filter.rs
  23. +240
    -0
      src/framed_app.rs
  24. +379
    -0
      src/framed_handler.rs
  25. +448
    -0
      src/framed_route.rs
  26. +1230
    -1122
      src/fs.rs
  27. +298
    -458
      src/handler.rs
  28. +0
    -159
      src/header/common/accept.rs
  29. +0
    -69
      src/header/common/accept_charset.rs
  30. +0
    -72
      src/header/common/accept_encoding.rs
  31. +0
    -75
      src/header/common/accept_language.rs
  32. +0
    -85
      src/header/common/allow.rs
  33. +0
    -254
      src/header/common/cache_control.rs
  34. +0
    -914
      src/header/common/content_disposition.rs
  35. +0
    -65
      src/header/common/content_language.rs
  36. +0
    -210
      src/header/common/content_range.rs
  37. +0
    -122
      src/header/common/content_type.rs
  38. +0
    -42
      src/header/common/date.rs
  39. +0
    -96
      src/header/common/etag.rs
  40. +0
    -39
      src/header/common/expires.rs
  41. +0
    -70
      src/header/common/if_match.rs
  42. +0
    -39
      src/header/common/if_modified_since.rs
  43. +0
    -92
      src/header/common/if_none_match.rs
  44. +0
    -115
      src/header/common/if_range.rs
  45. +0
    -40
      src/header/common/if_unmodified_since.rs
  46. +0
    -38
      src/header/common/last_modified.rs
  47. +0
    -350
      src/header/common/mod.rs
  48. +0
    -434
      src/header/common/range.rs
  49. +0
    -471
      src/header/mod.rs
  50. +0
    -152
      src/header/shared/charset.rs
  51. +0
    -59
      src/header/shared/encoding.rs
  52. +0
    -266
      src/header/shared/entity.rs
  53. +0
    -119
      src/header/shared/httpdate.rs
  54. +0
    -14
      src/header/shared/mod.rs
  55. +0
    -294
      src/header/shared/quality_item.rs
  56. +158
    -549
      src/helpers.rs
  57. +0
    -84
      src/httpcodes.rs
  58. +0
    -855
      src/httpmessage.rs
  59. +0
    -545
      src/httprequest.rs
  60. +0
    -1458
      src/httpresponse.rs
  61. +49
    -29
      src/info.rs
  62. +0
    -519
      src/json.rs
  63. +29
    -284
      src/lib.rs
  64. +443
    -0
      src/middleware/compress.rs
  65. +0
    -1227
      src/middleware/cors.rs
  66. +0
    -275
      src/middleware/csrf.rs
  67. +98
    -55
      src/middleware/defaultheaders.rs
  68. +0
    -141
      src/middleware/errhandlers.rs
  69. +0
    -399
      src/middleware/identity.rs
  70. +0
    -384
      src/middleware/logger.rs
  71. +50
    -53
      src/middleware/mod.rs
  72. +0
    -618
      src/middleware/session.rs
  73. +0
    -815
      src/multipart.rs
  74. +0
    -334
      src/param.rs
  75. +0
    -715
      src/payload.rs
  76. +0
    -869
      src/pipeline.rs
  77. +0
    -328
      src/pred.rs
  78. +174
    -0
      src/request.rs
  79. +332
    -181
      src/resource.rs
  80. +259
    -0
      src/responder.rs
  81. +382
    -514
      src/route.rs
  82. +0
    -1247
      src/router.rs
  83. +0
    -1236
      src/scope.rs
  84. +0
    -383
      src/server/acceptor.rs
  85. +0
    -134
      src/server/builder.rs
  86. +0
    -300
      src/server/channel.rs
  87. +0
    -108
      src/server/error.rs
  88. +0
    -1353
      src/server/h1.rs
  89. +0
    -541
      src/server/h1decoder.rs
  90. +0
    -364
      src/server/h1writer.rs
  91. +0
    -472
      src/server/h2.rs
  92. +0
    -268
      src/server/h2writer.rs
  93. +0
    -208
      src/server/handler.rs
  94. +0
    -208
      src/server/helpers.rs
  95. +0
    -579
      src/server/http.rs
  96. +0
    -69
      src/server/incoming.rs
  97. +0
    -288
      src/server/input.rs
  98. +0
    -284
      src/server/message.rs
  99. +0
    -370
      src/server/mod.rs
  100. +0
    -760
      src/server/output.rs

+ 2
- 830
CHANGES.md View File

@ -1,833 +1,5 @@
# Changes
## [x.x.xx] - xxxx-xx-xx
## [0.1.0] - 2018-10-x
### Added
* Add `from_file` and `from_file_with_config` to `NamedFile` to allow sending files without a known path. #670
* Add `insert` and `remove` methods to `HttpResponseBuilder`
### Fixed
* Ignored the `If-Modified-Since` if `If-None-Match` is specified. #680
## [0.7.18] - 2019-01-10
### Added
* Add `with_cookie` for `TestRequest` to allow users to customize request cookie. #647
* Add `cookie` method for `TestRequest` to allow users to add cookie dynamically.
### Fixed
* StaticFiles decode special characters in request's path
* Fix test server listener leak #654
## [0.7.17] - 2018-12-25
### Added
* Support for custom content types in `JsonConfig`. #637
* Send `HTTP/1.1 100 Continue` if request contains `expect: continue` header #634
### Fixed
* HTTP1 decoder should perform case-insentive comparison for client requests (e.g. `Keep-Alive`). #631
* Access-Control-Allow-Origin header should only a return a single, matching origin. #603
## [0.7.16] - 2018-12-11
### Added
* Implement `FromRequest` extractor for `Either<A,B>`
* Implement `ResponseError` for `SendError`
## [0.7.15] - 2018-12-05
### Changed
* `ClientConnector::resolver` now accepts `Into<Recipient>` instead of `Addr`. It enables user to implement own resolver.
* `QueryConfig` and `PathConfig` are made public.
* `AsyncResult::async` is changed to `AsyncResult::future` as `async` is reserved keyword in 2018 edition.
### Added
* By default, `Path` extractor now percent decode all characters. This behaviour can be disabled
with `PathConfig::default().disable_decoding()`
## [0.7.14] - 2018-11-14
### Added
* Add method to configure custom error handler to `Query` and `Path` extractors.
* Add method to configure `SameSite` option in `CookieIdentityPolicy`.
* By default, `Path` extractor now percent decode all characters. This behaviour can be disabled
with `PathConfig::default().disable_decoding()`
### Fixed
* Fix websockets connection drop if request contains "content-length" header #567
* Fix keep-alive timer reset
* HttpServer now treats streaming bodies the same for HTTP/1.x protocols. #549
* Set nodelay for socket #560
## [0.7.13] - 2018-10-14
### Fixed
* Fixed rustls support
* HttpServer not sending streamed request body on HTTP/2 requests #544
## [0.7.12] - 2018-10-10
### Changed
* Set min version for actix
* Set min version for actix-net
## [0.7.11] - 2018-10-09
### Fixed
* Fixed 204 responses for http/2
## [0.7.10] - 2018-10-09
### Fixed
* Fixed panic during graceful shutdown
## [0.7.9] - 2018-10-09
### Added
* Added client shutdown timeout setting
* Added slow request timeout setting
* Respond with 408 response on slow request timeout #523
### Fixed
* HTTP1 decoding errors are reported to the client. #512
* Correctly compose multiple allowed origins in CORS. #517
* Websocket server finished() isn't called if client disconnects #511
* Responses with the following codes: 100, 101, 102, 204 -- are sent without Content-Length header. #521
* Correct usage of `no_http2` flag in `bind_*` methods. #519
## [0.7.8] - 2018-09-17
### Added
* Use server `Keep-Alive` setting as slow request timeout #439
### Changed
* Use 5 seconds keep-alive timer by default.
### Fixed
* Fixed wrong error message for i16 type #510
## [0.7.7] - 2018-09-11
### Fixed
* Fix linked list of HttpChannels #504
* Fix requests to TestServer fail #508
## [0.7.6] - 2018-09-07
### Fixed
* Fix system_exit in HttpServer #501
* Fix parsing of route param containin regexes with repetition #500
### Changes
* Unhide `SessionBackend` and `SessionImpl` traits #455
## [0.7.5] - 2018-09-04
### Added
* Added the ability to pass a custom `TlsConnector`.
* Allow to register handlers on scope level #465
### Fixed
* Handle socket read disconnect
* Handling scoped paths without leading slashes #460
### Changed
* Read client response until eof if connection header set to close #464
## [0.7.4] - 2018-08-23
### Added
* Added `HttpServer::maxconn()` and `HttpServer::maxconnrate()`,
accept backpressure #250
* Allow to customize connection handshake process via `HttpServer::listen_with()`
and `HttpServer::bind_with()` methods
* Support making client connections via `tokio-uds`'s `UnixStream` when "uds" feature is enabled #472
### Changed
* It is allowed to use function with up to 10 parameters for handler with `extractor parameters`.
`Route::with_config()`/`Route::with_async_config()` always passes configuration objects as tuple
even for handler with one parameter.
* native-tls - 0.2
* `Content-Disposition` is re-worked. Its parser is now more robust and handles quoted content better. See #461
### Fixed
* Use zlib instead of raw deflate for decoding and encoding payloads with
`Content-Encoding: deflate`.
* Fixed headers formating for CORS Middleware Access-Control-Expose-Headers #436
* Fix adding multiple response headers #446
* Client includes port in HOST header when it is not default(e.g. not 80 and 443). #448
* Panic during access without routing being set #452
* Fixed http/2 error handling
### Deprecated
* `HttpServer::no_http2()` is deprecated, use `OpensslAcceptor::with_flags()` or
`RustlsAcceptor::with_flags()` instead
* `HttpServer::listen_tls()`, `HttpServer::listen_ssl()`, `HttpServer::listen_rustls()` have been
deprecated in favor of `HttpServer::listen_with()` with specific `acceptor`.
* `HttpServer::bind_tls()`, `HttpServer::bind_ssl()`, `HttpServer::bind_rustls()` have been
deprecated in favor of `HttpServer::bind_with()` with specific `acceptor`.
## [0.7.3] - 2018-08-01
### Added
* Support HTTP/2 with rustls #36
* Allow TestServer to open a websocket on any URL (TestServer::ws_at()) #433
### Fixed
* Fixed failure 0.1.2 compatibility
* Do not override HOST header for client request #428
* Gz streaming, use `flate2::write::GzDecoder` #228
* HttpRequest::url_for is not working with scopes #429
* Fixed headers' formating for CORS Middleware `Access-Control-Expose-Headers` header value to HTTP/1.1 & HTTP/2 spec-compliant format #436
## [0.7.2] - 2018-07-26
### Added
* Add implementation of `FromRequest<S>` for `Option<T>` and `Result<T, Error>`
* Allow to handle application prefix, i.e. allow to handle `/app` path
for application with `/app` prefix.
Check [`App::prefix()`](https://actix.rs/actix-web/actix_web/struct.App.html#method.prefix)
api doc.
* Add `CookieSessionBackend::http_only` method to set `HttpOnly` directive of cookies
### Changed
* Upgrade to cookie 0.11
* Removed the timestamp from the default logger middleware
### Fixed
* Missing response header "content-encoding" #421
* Fix stream draining for http/2 connections #290
## [0.7.1] - 2018-07-21
### Fixed
* Fixed default_resource 'not yet implemented' panic #410
## [0.7.0] - 2018-07-21
### Added
* Add `fs::StaticFileConfig` to provide means of customizing static
file services. It allows to map `mime` to `Content-Disposition`,
specify whether to use `ETag` and `Last-Modified` and allowed methods.
* Add `.has_prefixed_resource()` method to `router::ResourceInfo`
for route matching with prefix awareness
* Add `HttpMessage::readlines()` for reading line by line.
* Add `ClientRequestBuilder::form()` for sending `application/x-www-form-urlencoded` requests.
* Add method to configure custom error handler to `Form` extractor.
* Add methods to `HttpResponse` to retrieve, add, and delete cookies
* Add `.set_content_type()` and `.set_content_disposition()` methods
to `fs::NamedFile` to allow overriding the values inferred by default
* Add `fs::file_extension_to_mime()` helper function to get the MIME
type for a file extension
* Add `.content_disposition()` method to parse Content-Disposition of
multipart fields
* Re-export `actix::prelude::*` as `actix_web::actix` module.
* `HttpRequest::url_for_static()` for a named route with no variables segments
* Propagation of the application's default resource to scopes that haven't set a default resource.
### Changed
* Min rustc version is 1.26
* Use tokio instead of tokio-core
* `CookieSessionBackend` sets percent encoded cookies for outgoing HTTP messages.
* Became possible to use enums with query extractor.
Issue [#371](https://github.com/actix/actix-web/issues/371).
[Example](https://github.com/actix/actix-web/blob/master/tests/test_handlers.rs#L94-L134)
* `HttpResponse::into_builder()` now moves cookies into the builder
instead of dropping them
* For safety and performance reasons `Handler::handle()` uses `&self` instead of `&mut self`
* `Handler::handle()` uses `&HttpRequest` instead of `HttpRequest`
* Added header `User-Agent: Actix-web/<current_version>` to default headers when building a request
* port `Extensions` type from http create, we don't need `Send + Sync`
* `HttpRequest::query()` returns `Ref<HashMap<String, String>>`
* `HttpRequest::cookies()` returns `Ref<Vec<Cookie<'static>>>`
* `StaticFiles::new()` returns `Result<StaticFiles<S>, Error>` instead of `StaticFiles<S>`
* `StaticFiles` uses the default handler if the file does not exist
### Removed
* Remove `Route::with2()` and `Route::with3()` use tuple of extractors instead.
* Remove `HttpMessage::range()`
## [0.6.15] - 2018-07-11
### Fixed
* Fix h2 compatibility #352
* Fix duplicate tail of StaticFiles with index_file. #344
## [0.6.14] - 2018-06-21
### Added
* Allow to disable masking for websockets client
### Fixed
* SendRequest execution fails with the "internal error: entered unreachable code" #329
## [0.6.13] - 2018-06-11
* http/2 end-of-frame is not set if body is empty bytes #307
* InternalError can trigger memory unsafety #301
## [0.6.12] - 2018-06-08
### Added
* Add `Host` filter #287
* Allow to filter applications
* Improved failure interoperability with downcasting #285
* Allow to use custom resolver for `ClientConnector`
## [0.6.11] - 2018-06-05
* Support chunked encoding for UrlEncoded body #262
* `HttpRequest::url_for()` for a named route with no variables segments #265
* `Middleware::response()` is not invoked if error result was returned by another `Middleware::start()` #255
* CORS: Do not validate Origin header on non-OPTION requests #271
* Fix multipart upload "Incomplete" error #282
## [0.6.10] - 2018-05-24
### Added
* Allow to use path without trailing slashes for scope registration #241
* Allow to set encoding for exact NamedFile #239
### Fixed
* `TestServer::post()` actually sends `GET` request #240
## 0.6.9 (2018-05-22)
* Drop connection if request's payload is not fully consumed #236
* Fix streaming response with body compression
## 0.6.8 (2018-05-20)
* Fix scope resource path extractor #234
* Re-use tcp listener on pause/resume
## 0.6.7 (2018-05-17)
* Fix compilation with --no-default-features
## 0.6.6 (2018-05-17)
* Panic during middleware execution #226
* Add support for listen_tls/listen_ssl #224
* Implement extractor for `Session`
* Ranges header support for NamedFile #60
## 0.6.5 (2018-05-15)
* Fix error handling during request decoding #222
## 0.6.4 (2018-05-11)
* Fix segfault in ServerSettings::get_response_builder()
## 0.6.3 (2018-05-10)
* Add `Router::with_async()` method for async handler registration.
* Added error response functions for 501,502,503,504
* Fix client request timeout handling
## 0.6.2 (2018-05-09)
* WsWriter trait is optional.
## 0.6.1 (2018-05-08)
* Fix http/2 payload streaming #215
* Fix connector's default `keep-alive` and `lifetime` settings #212
* Send `ErrorNotFound` instead of `ErrorBadRequest` when path extractor fails #214
* Allow to exclude certain endpoints from logging #211
## 0.6.0 (2018-05-08)
* Add route scopes #202
* Allow to use ssl and non-ssl connections at the same time #206
* Websocket CloseCode Empty/Status is ambiguous #193
* Add Content-Disposition to NamedFile #204
* Allow to access Error's backtrace object
* Allow to override files listing renderer for `StaticFiles` #203
* Various extractor usability improvements #207
## 0.5.6 (2018-04-24)
* Make flate2 crate optional #200
## 0.5.5 (2018-04-24)
* Fix panic when Websocket is closed with no error code #191
* Allow to use rust backend for flate2 crate #199
## 0.5.4 (2018-04-19)
* Add identity service middleware
* Middleware response() is not invoked if there was an error in async handler #187
* Use Display formatting for InternalError Display implementation #188
## 0.5.3 (2018-04-18)
* Impossible to quote slashes in path parameters #182
## 0.5.2 (2018-04-16)
* Allow to configure StaticFiles's CpuPool, via static method or env variable
* Add support for custom handling of Json extractor errors #181
* Fix StaticFiles does not support percent encoded paths #177
* Fix Client Request with custom Body Stream halting on certain size requests #176
## 0.5.1 (2018-04-12)
* Client connector provides stats, `ClientConnector::stats()`
* Fix end-of-stream handling in parse_payload #173
* Fix StaticFiles generate a lot of threads #174
## 0.5.0 (2018-04-10)
* Type-safe path/query/form parameter handling, using serde #70
* HttpResponse builder's methods `.body()`, `.finish()`, `.json()`
return `HttpResponse` instead of `Result`
* Use more ergonomic `actix_web::Error` instead of `http::Error` for `ClientRequestBuilder::body()`
* Added `signed` and `private` `CookieSessionBackend`s
* Added `HttpRequest::resource()`, returns current matched resource
* Added `ErrorHandlers` middleware
* Fix router cannot parse Non-ASCII characters in URL #137
* Fix client connection pooling
* Fix long client urls #129
* Fix panic on invalid URL characters #130
* Fix logger request duration calculation #152
* Fix prefix and static file serving #168
## 0.4.10 (2018-03-20)
* Use `Error` instead of `InternalError` for `error::ErrorXXXX` methods
* Allow to set client request timeout
* Allow to set client websocket handshake timeout
* Refactor `TestServer` configuration
* Fix server websockets big payloads support
* Fix http/2 date header generation
## 0.4.9 (2018-03-16)
* Allow to disable http/2 support
* Wake payload reading task when data is available
* Fix server keep-alive handling
* Send Query Parameters in client requests #120
* Move brotli encoding to a feature
* Add option of default handler for `StaticFiles` handler #57
* Add basic client connection pooling
## 0.4.8 (2018-03-12)
* Allow to set read buffer capacity for server request
* Handle WouldBlock error for socket accept call
## 0.4.7 (2018-03-11)
* Fix panic on unknown content encoding
* Fix connection get closed too early
* Fix streaming response handling for http/2
* Better sleep on error support
## 0.4.6 (2018-03-10)
* Fix client cookie handling
* Fix json content type detection
* Fix CORS middleware #117
* Optimize websockets stream support
## 0.4.5 (2018-03-07)
* Fix compression #103 and #104
* Fix client cookie handling #111
* Non-blocking processing of a `NamedFile`
* Enable compression support for `NamedFile`
* Better support for `NamedFile` type
* Add `ResponseError` impl for `SendRequestError`. This improves ergonomics of the client.
* Add native-tls support for client
* Allow client connection timeout to be set #108
* Allow to use std::net::TcpListener for HttpServer
* Handle panics in worker threads
## 0.4.4 (2018-03-04)
* Allow to use Arc<Vec<u8>> as response/request body
* Fix handling of requests with an encoded body with a length > 8192 #93
## 0.4.3 (2018-03-03)
* Fix request body read bug
* Fix segmentation fault #79
* Set reuse address before bind #90
## 0.4.2 (2018-03-02)
* Better naming for websockets implementation
* Add `Pattern::with_prefix()`, make it more usable outside of actix
* Add csrf middleware for filter for cross-site request forgery #89
* Fix disconnect on idle connections
## 0.4.1 (2018-03-01)
* Rename `Route::p()` to `Route::filter()`
* Better naming for http codes
* Fix payload parse in situation when socket data is not ready.
* Fix Session mutable borrow lifetime #87
## 0.4.0 (2018-02-28)
* Actix 0.5 compatibility
* Fix request json/urlencoded loaders
* Simplify HttpServer type definition
* Added HttpRequest::encoding() method
* Added HttpRequest::mime_type() method
* Added HttpRequest::uri_mut(), allows to modify request uri
* Added StaticFiles::index_file()
* Added http client
* Added websocket client
* Added TestServer::ws(), test websockets client
* Added TestServer http client support
* Allow to override content encoding on application level
## 0.3.3 (2018-01-25)
* Stop processing any events after context stop
* Re-enable write back-pressure for h1 connections
* Refactor HttpServer::start_ssl() method
* Upgrade openssl to 0.10
## 0.3.2 (2018-01-21)
* Fix HEAD requests handling
* Log request processing errors
* Always enable content encoding if encoding explicitly selected
* Allow multiple Applications on a single server with different state #49
* CORS middleware: allowed_headers is defaulting to None #50
## 0.3.1 (2018-01-13)
* Fix directory entry path #47
* Do not enable chunked encoding for HTTP/1.0
* Allow explicitly disable chunked encoding
## 0.3.0 (2018-01-12)
* HTTP/2 Support
* Refactor streaming responses
* Refactor error handling
* Asynchronous middlewares
* Refactor logger middleware
* Content compression/decompression (br, gzip, deflate)
* Server multi-threading
* Graceful shutdown support
## 0.2.1 (2017-11-03)
* Allow to start tls server with `HttpServer::serve_tls`
* Export `Frame` enum
* Add conversion impl from `HttpResponse` and `BinaryBody` to a `Frame`
## 0.2.0 (2017-10-30)
* Do not use `http::Uri` as it can not parse some valid paths
* Refactor response `Body`
* Refactor `RouteRecognizer` usability
* Refactor `HttpContext::write`
* Refactor `Payload` stream
* Re-use `BinaryBody` for `Frame::Payload`
* Stop http actor on `write_eof`
* Fix disconnection handling.
## 0.1.0 (2017-10-23)
* First release
* Initial impl

+ 36
- 86
Cargo.toml View File

@ -1,6 +1,6 @@
[package]
name = "actix-web"
version = "0.7.18"
version = "0.1.0"
authors = ["Nikolay Kim <fafhrd91@gmail.com>"]
description = "Actix web is a simple, pragmatic and extremely fast web framework for Rust."
readme = "README.md"
@ -10,44 +10,21 @@ repository = "https://github.com/actix/actix-web.git"
documentation = "https://actix.rs/api/actix-web/stable/actix_web/"
categories = ["network-programming", "asynchronous",
"web-programming::http-server",
"web-programming::http-client",
"web-programming::websocket"]
license = "MIT/Apache-2.0"
exclude = [".gitignore", ".travis.yml", ".cargo/config", "appveyor.yml"]
build = "build.rs"
[package.metadata.docs.rs]
features = ["tls", "ssl", "rust-tls", "session", "brotli", "flate2-c"]
edition = "2018"
[badges]
travis-ci = { repository = "actix/actix-web", branch = "master" }
appveyor = { repository = "fafhrd91/actix-web-hdy9d" }
codecov = { repository = "actix/actix-web", branch = "master", service = "github" }
travis-ci = { repository = "actix/actix-web2", branch = "master" }
codecov = { repository = "actix/actix-web2", branch = "master", service = "github" }
[lib]
name = "actix_web"
path = "src/lib.rs"
[features]
default = ["session", "brotli", "flate2-c", "cell"]
# tls
tls = ["native-tls", "tokio-tls", "actix-net/tls"]
# openssl
ssl = ["openssl", "tokio-openssl", "actix-net/ssl"]
# deprecated, use "ssl"
alpn = ["openssl", "tokio-openssl", "actix-net/ssl"]
# rustls
rust-tls = ["rustls", "tokio-rustls", "webpki", "webpki-roots", "actix-net/rust-tls"]
# unix sockets
uds = ["tokio-uds"]
# sessions feature, session require "ring" crate and c compiler
session = ["cookie/secure"]
default = ["brotli", "flate2-c"]
# brotli encoding, requires c compiler
brotli = ["brotli2"]
@ -58,81 +35,54 @@ flate2-c = ["flate2/miniz-sys"]
# rust backend for flate2 crate
flate2-rust = ["flate2/rust_backend"]
cell = ["actix-net/cell"]
[dependencies]
actix = "0.7.9"
actix-net = "0.2.6"
actix-codec = "0.1.0"
#actix-service = "0.2.1"
#actix-server = "0.2.1"
#actix-utils = "0.2.1"
actix-service = { git = "https://github.com/actix/actix-net.git" }
actix-server = { git = "https://github.com/actix/actix-net.git" }
actix-utils = { git = "https://github.com/actix/actix-net.git" }
actix-rt = "0.1.0"
actix-http = { git = "https://github.com/actix/actix-http.git" }
actix-router = { git = "https://github.com/actix/actix-net.git" }
v_htmlescape = "0.4"
base64 = "0.10"
bitflags = "1.0"
failure = "^0.1.2"
h2 = "0.1"
http = "^0.1.14"
httparse = "1.3"
bytes = "0.4"
futures = "0.1"
derive_more = "0.14"
log = "0.4"
lazy_static = "1.2"
mime = "0.3"
mime_guess = "2.0.0-alpha"
num_cpus = "1.0"
num_cpus = "1.10"
percent-encoding = "1.0"
rand = "0.6"
regex = "1.0"
cookie = { version="0.11", features=["percent-encode"] }
v_htmlescape = "0.4"
serde = "1.0"
serde_json = "1.0"
sha1 = "0.6"
smallvec = "0.6"
time = "0.1"
encoding = "0.2"
language-tags = "0.2"
lazy_static = "1.0"
lazycell = "1.0.0"
parking_lot = "0.7"
serde_urlencoded = "^0.5.3"
url = { version="1.7", features=["query_encoding"] }
cookie = { version="0.11", features=["percent-encode"] }
parking_lot = "0.7"
hashbrown = "0.1"
regex = "1"
time = "0.1"
threadpool = "1.7"
# compression
brotli2 = { version="^0.3.2", optional = true }
flate2 = { version="^1.0.2", optional = true, default-features = false }
# io
mio = "^0.6.13"
net2 = "0.2"
bytes = "0.4"
byteorder = "1.2"
futures = "0.1"
futures-cpupool = "0.1"
slab = "0.4"
tokio = "0.1"
tokio-io = "0.1"
tokio-tcp = "0.1"
tokio-timer = "0.2.8"
tokio-reactor = "0.1"
tokio-current-thread = "0.1"
# native-tls
native-tls = { version="0.2", optional = true }
tokio-tls = { version="0.2", optional = true }
# openssl
openssl = { version="0.10", optional = true }
tokio-openssl = { version="0.2", optional = true }
#rustls
rustls = { version = "0.14", optional = true }
tokio-rustls = { version = "0.8", optional = true }
webpki = { version = "0.18", optional = true }
webpki-roots = { version = "0.15", optional = true }
# unix sockets
tokio-uds = { version="0.2", optional = true }
[dev-dependencies]
actix-rt = "0.1.0"
#actix-server = { version="0.2", features=["ssl"] }
actix-server = { git = "https://github.com/actix/actix-net.git", features=["ssl"] }
actix-http = { git = "https://github.com/actix/actix-http.git", features=["ssl"] }
actix-http-test = { git = "https://github.com/actix/actix-http.git", features=["ssl"] }
rand = "0.6"
env_logger = "0.6"
serde_derive = "1.0"
[build-dependencies]
version_check = "0.1"
[profile.release]
lto = true
opt-level = 3


+ 0
- 16
build.rs View File

@ -1,16 +0,0 @@
extern crate version_check;
fn main() {
match version_check::is_min_version("1.26.0") {
Some((true, _)) => println!("cargo:rustc-cfg=actix_impl_trait"),
_ => (),
};
match version_check::is_nightly() {
Some(true) => {
println!("cargo:rustc-cfg=actix_nightly");
println!("cargo:rustc-cfg=actix_impl_trait");
}
Some(false) => (),
None => (),
};
}

+ 54
- 0
examples/basic.rs View File

@ -0,0 +1,54 @@
use futures::IntoFuture;
use actix_http::{h1, http::Method, Response};
use actix_server::Server;
use actix_web2::{middleware, App, Error, HttpRequest, Resource};
fn index(req: HttpRequest) -> &'static str {
println!("REQ: {:?}", req);
"Hello world!\r\n"
}
fn index_async(req: HttpRequest) -> impl IntoFuture<Item = &'static str, Error = Error> {
println!("REQ: {:?}", req);
Ok("Hello world!\r\n")
}
fn no_params() -> &'static str {
"Hello world!\r\n"
}
fn main() {
::std::env::set_var("RUST_LOG", "actix_server=info,actix_web2=info");
env_logger::init();
let sys = actix_rt::System::new("hello-world");
Server::build()
.bind("test", "127.0.0.1:8080", || {
h1::H1Service::new(
App::new()
.middleware(
middleware::DefaultHeaders::new().header("X-Version", "0.2"),
)
.middleware(middleware::Compress::default())
.resource("/resource1/index.html", |r| r.get(index))
.service(
"/resource2/index.html",
Resource::new()
.middleware(
middleware::DefaultHeaders::new()
.header("X-Version-R2", "0.3"),
)
.default_resource(|r| r.to(|| Response::MethodNotAllowed()))
.method(Method::GET, |r| r.to_async(index_async)),
)
.service("/test1.html", Resource::new().to(|| "Test\r\n"))
.service("/", Resource::new().to(no_params)),
)
})
.unwrap()
.workers(1)
.start();
let _ = sys.run();
}

+ 0
- 3
rustfmt.toml View File

@ -1,5 +1,2 @@
max_width = 89
reorder_imports = true
#wrap_comments = true
fn_args_density = "Compressed"
#use_small_heuristics = false

+ 648
- 0
src/app.rs View File

@ -0,0 +1,648 @@
use std::cell::RefCell;
use std::marker::PhantomData;
use std::rc::Rc;
use actix_http::body::{Body, MessageBody};
use actix_http::{Extensions, PayloadStream, Request, Response};
use actix_router::{Path, ResourceDef, ResourceInfo, Router, Url};
use actix_service::{
AndThenNewService, ApplyNewService, IntoNewService, IntoNewTransform, NewService,
NewTransform, Service,
};
use futures::future::{ok, Either, FutureResult};
use futures::{Async, Future, IntoFuture, Poll};
use crate::helpers::{
BoxedHttpNewService, BoxedHttpService, DefaultNewService, HttpDefaultNewService,
};
use crate::resource::Resource;
use crate::service::{ServiceRequest, ServiceResponse};
use crate::state::{State, StateFactory, StateFactoryResult};
type BoxedResponse = Box<Future<Item = ServiceResponse, Error = ()>>;
pub trait HttpServiceFactory<Request> {
type Factory: NewService<Request = Request>;
fn rdef(&self) -> &ResourceDef;
fn create(self) -> Self::Factory;
}
/// Application builder
pub struct App<P, B, T> {
services: Vec<(
ResourceDef,
BoxedHttpNewService<ServiceRequest<P>, ServiceResponse>,
)>,
default: Option<Rc<HttpDefaultNewService<ServiceRequest<P>, ServiceResponse>>>,
defaults: Vec<
Rc<
RefCell<
Option<Rc<HttpDefaultNewService<ServiceRequest<P>, ServiceResponse>>>,
>,
>,
>,
endpoint: T,
factory_ref: Rc<RefCell<Option<AppFactory<P>>>>,
extensions: Extensions,
state: Vec<Box<StateFactory>>,
_t: PhantomData<(P, B)>,
}
impl App<PayloadStream, Body, AppEntry<PayloadStream>> {
/// Create application with empty state. Application can
/// be configured with a builder-like pattern.
pub fn new() -> Self {
App::create()
}
}
impl Default for App<PayloadStream, Body, AppEntry<PayloadStream>> {
fn default() -> Self {
App::new()
}
}
impl App<PayloadStream, Body, AppEntry<PayloadStream>> {
/// Create application with specified state. Application can be
/// configured with a builder-like pattern.
///
/// State is shared with all resources within same application and
/// could be accessed with `HttpRequest::state()` method.
///
/// **Note**: http server accepts an application factory rather than
/// an application instance. Http server constructs an application
/// instance for each thread, thus application state must be constructed
/// multiple times. If you want to share state between different
/// threads, a shared object should be used, e.g. `Arc`. Application
/// state does not need to be `Send` or `Sync`.
pub fn state<S: 'static>(mut self, state: S) -> Self {
self.state.push(Box::new(State::new(state)));
self
}
/// Set application state. This function is
/// similar to `.state()` but it accepts state factory. State get
/// constructed asynchronously during application initialization.
pub fn state_factory<S, F, Out>(mut self, state: F) -> Self
where
F: Fn() -> Out + 'static,
Out: IntoFuture + 'static,
Out::Error: std::fmt::Debug,
{
self.state.push(Box::new(State::new(state)));
self
}
fn create() -> Self {
let fref = Rc::new(RefCell::new(None));
App {
services: Vec::new(),
default: None,
defaults: Vec::new(),
endpoint: AppEntry::new(fref.clone()),
factory_ref: fref,
extensions: Extensions::new(),
state: Vec::new(),
_t: PhantomData,
}
}
}
// /// Application router builder
// pub struct AppRouter<S, T, P> {
// services: Vec<(
// ResourceDef,
// BoxedHttpNewService<ServiceRequest<P>, Response>,
// )>,
// default: Option<Rc<HttpDefaultNewService<ServiceRequest<P>, Response>>>,
// defaults:
// Vec<Rc<RefCell<Option<Rc<HttpDefaultNewService<ServiceRequest<P>, Response>>>>>>,
// state: AppState<S>,
// endpoint: T,
// factory_ref: Rc<RefCell<Option<AppFactory<P>>>>,
// extensions: Extensions,
// _t: PhantomData<P>,
// }
impl<P, B, T> App<P, B, T>
where
P: 'static,
B: MessageBody,
T: NewService<
Request = ServiceRequest<P>,
Response = ServiceResponse<B>,
Error = (),
InitError = (),
>,
{
/// Configure resource for a specific path.
///
/// Resources may have variable path segments. For example, a
/// resource with the path `/a/{name}/c` would match all incoming
/// requests with paths such as `/a/b/c`, `/a/1/c`, or `/a/etc/c`.
///
/// A variable segment is specified in the form `{identifier}`,
/// where the identifier can be used later in a request handler to
/// access the matched value for that segment. This is done by
/// looking up the identifier in the `Params` object returned by
/// `HttpRequest.match_info()` method.
///
/// By default, each segment matches the regular expression `[^{}/]+`.
///
/// You can also specify a custom regex in the form `{identifier:regex}`:
///
/// For instance, to route `GET`-requests on any route matching
/// `/users/{userid}/{friend}` and store `userid` and `friend` in
/// the exposed `Params` object:
///
/// ```rust,ignore
/// # extern crate actix_web;
/// use actix_web::{http, App, HttpResponse};
///
/// fn main() {
/// let app = App::new().resource("/users/{userid}/{friend}", |r| {
/// r.get(|r| r.to(|_| HttpResponse::Ok()));
/// r.head(|r| r.to(|_| HttpResponse::MethodNotAllowed()))
/// });
/// }
/// ```
pub fn resource<F, U>(mut self, path: &str, f: F) -> Self
where
F: FnOnce(Resource<P>) -> Resource<P, U>,
U: NewService<
Request = ServiceRequest<P>,
Response = ServiceResponse,
Error = (),
InitError = (),
> + 'static,
{
let rdef = ResourceDef::new(path);
let resource = f(Resource::new());
self.defaults.push(resource.get_default());
self.services.push((
rdef,
Box::new(HttpNewService::new(resource.into_new_service())),
));
self
}
/// Default resource to be used if no matching route could be found.
///
/// Default resource works with resources only and does not work with
/// custom services.
pub fn default_resource<F, R, U>(mut self, f: F) -> Self
where
F: FnOnce(Resource<P>) -> R,
R: IntoNewService<U>,
U: NewService<
Request = ServiceRequest<P>,
Response = ServiceResponse,
Error = (),
> + 'static,
{
// create and configure default resource
self.default = Some(Rc::new(Box::new(DefaultNewService::new(
f(Resource::new()).into_new_service(),
))));
self
}
/// Register resource handler service.
pub fn service<R, F, U>(mut self, rdef: R, factory: F) -> Self
where
R: Into<ResourceDef>,
F: IntoNewService<U>,
U: NewService<
Request = ServiceRequest<P>,
Response = ServiceResponse,
Error = (),
> + 'static,
{
self.services.push((
rdef.into(),
Box::new(HttpNewService::new(factory.into_new_service())),
));
self
}
/// Register a middleware.
pub fn middleware<M, B1, F>(
self,
mw: F,
) -> App<
P,
B1,
impl NewService<
Request = ServiceRequest<P>,
Response = ServiceResponse<B1>,
Error = (),
InitError = (),
>,
>
where
M: NewTransform<
T::Service,
Request = ServiceRequest<P>,
Response = ServiceResponse<B1>,
Error = (),
InitError = (),
>,
B1: MessageBody,
F: IntoNewTransform<M, T::Service>,
{
let endpoint = ApplyNewService::new(mw, self.endpoint);
App {
endpoint,
state: self.state,
services: self.services,
default: self.default,
defaults: Vec::new(),
factory_ref: self.factory_ref,
extensions: Extensions::new(),
_t: PhantomData,
}
}
/// Register an external resource.
///
/// External resources are useful for URL generation purposes only
/// and are never considered for matching at request time. Calls to
/// `HttpRequest::url_for()` will work as expected.
///
/// ```rust,ignore
/// # extern crate actix_web;
/// use actix_web::{App, HttpRequest, HttpResponse, Result};
///
/// fn index(req: &HttpRequest) -> Result<HttpResponse> {
/// let url = req.url_for("youtube", &["oHg5SJYRHA0"])?;
/// assert_eq!(url.as_str(), "https://youtube.com/watch/oHg5SJYRHA0");
/// Ok(HttpResponse::Ok().into())
/// }
///
/// fn main() {
/// let app = App::new()
/// .resource("/index.html", |r| r.get().f(index))
/// .external_resource("youtube", "https://youtube.com/watch/{video_id}")
/// .finish();
/// }
/// ```
pub fn external_resource<N, U>(self, _name: N, _url: U) -> Self
where
N: AsRef<str>,
U: AsRef<str>,
{
// self.parts
// .as_mut()
// .expect("Use after finish")
// .router
// .register_external(name.as_ref(), ResourceDef::external(url.as_ref()));
self
}
}
impl<T, P: 'static, B: MessageBody>
IntoNewService<AndThenNewService<AppStateFactory<P>, T, ()>> for App<P, B, T>
where
T: NewService<
Request = ServiceRequest<P>,
Response = ServiceResponse<B>,
Error = (),
InitError = (),
>,
{
fn into_new_service(self) -> AndThenNewService<AppStateFactory<P>, T, ()> {
// update resource default service
if self.default.is_some() {
for default in &self.defaults {
if default.borrow_mut().is_none() {
*default.borrow_mut() = self.default.clone();
}
}
}
// set factory
*self.factory_ref.borrow_mut() = Some(AppFactory {
services: Rc::new(self.services),
});
AppStateFactory {
state: self.state,
extensions: Rc::new(RefCell::new(Rc::new(self.extensions))),
_t: PhantomData,
}
.and_then(self.endpoint)
}
}
/// Service factory to convert `Request` to a `ServiceRequest<S>`
pub struct AppStateFactory<P> {
state: Vec<Box<StateFactory>>,
extensions: Rc<RefCell<Rc<Extensions>>>,
_t: PhantomData<P>,
}
impl<P: 'static> NewService for AppStateFactory<P> {
type Request = Request<P>;
type Response = ServiceRequest<P>;
type Error = ();
type InitError = ();
type Service = AppStateService<P>;
type Future = AppStateFactoryResult<P>;
fn new_service(&self, _: &()) -> Self::Future {
AppStateFactoryResult {
state: self.state.iter().map(|s| s.construct()).collect(),
extensions: self.extensions.clone(),
_t: PhantomData,
}
}
}
#[doc(hidden)]
pub struct AppStateFactoryResult<P> {
state: Vec<Box<StateFactoryResult>>,
extensions: Rc<RefCell<Rc<Extensions>>>,
_t: PhantomData<P>,
}
impl<P> Future for AppStateFactoryResult<P> {
type Item = AppStateService<P>;
type Error = ();
fn poll(&mut self) -> Poll<Self::Item, Self::Error> {
if let Some(extensions) = Rc::get_mut(&mut *self.extensions.borrow_mut()) {
let mut idx = 0;
while idx < self.state.len() {
if let Async::Ready(_) = self.state[idx].poll_result(extensions)? {
self.state.remove(idx);
} else {
idx += 1;
}
}
if !self.state.is_empty() {
return Ok(Async::NotReady);
}
} else {
log::warn!("Multiple copies of app extensions exists");
}
Ok(Async::Ready(AppStateService {
extensions: self.extensions.borrow().clone(),
_t: PhantomData,
}))
}
}
/// Service to convert `Request` to a `ServiceRequest<S>`
pub struct AppStateService<P> {
extensions: Rc<Extensions>,
_t: PhantomData<P>,
}
impl<P> Service for AppStateService<P> {
type Request = Request<P>;
type Response = ServiceRequest<P>;
type Error = ();
type Future = FutureResult<Self::Response, Self::Error>;
fn poll_ready(&mut self) -> Poll<(), Self::Error> {
Ok(Async::Ready(()))
}
fn call(&mut self, req: Request<P>) -> Self::Future {
ok(ServiceRequest::new(
Path::new(Url::new(req.uri().clone())),
req,
self.extensions.clone(),
))
}
}
pub struct AppFactory<P> {
services: Rc<
Vec<(
ResourceDef,
BoxedHttpNewService<ServiceRequest<P>, ServiceResponse>,
)>,
>,
}
impl<P> NewService for AppFactory<P> {
type Request = ServiceRequest<P>;
type Response = ServiceResponse;
type Error = ();
type InitError = ();
type Service = AppService<P>;
type Future = CreateAppService<P>;
fn new_service(&self, _: &()) -> Self::Future {
CreateAppService {
fut: self
.services
.iter()
.map(|(path, service)| {
CreateAppServiceItem::Future(
Some(path.clone()),
service.new_service(&()),
)
})
.collect(),
}
}
}
type HttpServiceFut<P> =
Box<Future<Item = BoxedHttpService<ServiceRequest<P>, ServiceResponse>, Error = ()>>;
/// Create app service
#[doc(hidden)]
pub struct CreateAppService<P> {
fut: Vec<CreateAppServiceItem<P>>,
}
enum CreateAppServiceItem<P> {
Future(Option<ResourceDef>, HttpServiceFut<P>),
Service(
ResourceDef,
BoxedHttpService<ServiceRequest<P>, ServiceResponse>,
),
}
impl<P> Future for CreateAppService<P> {
type Item = AppService<P>;
type Error = ();
fn poll(&mut self) -> Poll<Self::Item, Self::Error> {
let mut done = true;
// poll http services
for item in &mut self.fut {
let res = match item {
CreateAppServiceItem::Future(ref mut path, ref mut fut) => {
match fut.poll()? {
Async::Ready(service) => Some((path.take().unwrap(), service)),
Async::NotReady => {
done = false;
None
}
}
}
CreateAppServiceItem::Service(_, _) => continue,
};
if let Some((path, service)) = res {
*item = CreateAppServiceItem::Service(path, service);
}
}
if done {
let router = self
.fut
.drain(..)
.fold(Router::build(), |mut router, item| {
match item {
CreateAppServiceItem::Service(path, service) => {
router.rdef(path, service)
}
CreateAppServiceItem::Future(_, _) => unreachable!(),
}
router
});
Ok(Async::Ready(AppService {
router: router.finish(),
ready: None,
}))
} else {
Ok(Async::NotReady)
}
}
}
pub struct AppService<P> {
router: Router<BoxedHttpService<ServiceRequest<P>, ServiceResponse>>,
ready: Option<(ServiceRequest<P>, ResourceInfo)>,
}
impl<P> Service for AppService<P> {
type Request = ServiceRequest<P>;
type Response = ServiceResponse;
type Error = ();
type Future = Either<BoxedResponse, FutureResult<Self::Response, Self::Error>>;
fn poll_ready(&mut self) -> Poll<(), Self::Error> {
if self.ready.is_none() {
Ok(Async::Ready(()))
} else {
Ok(Async::NotReady)
}
}
fn call(&mut self, mut req: ServiceRequest<P>) -> Self::Future {
if let Some((srv, _info)) = self.router.recognize_mut(req.match_info_mut()) {
Either::A(srv.call(req))
} else {
let req = req.into_request();
Either::B(ok(ServiceResponse::new(req, Response::NotFound().finish())))
}
}
}
pub struct AppServiceResponse(Box<Future<Item = ServiceResponse, Error = ()>>);
impl Future for AppServiceResponse {
type Item = ServiceResponse;
type Error = ();
fn poll(&mut self) -> Poll<Self::Item, Self::Error> {
self.0.poll().map_err(|_| panic!())
}
}
struct HttpNewService<P: 'static, T: NewService<Request = ServiceRequest<P>>>(T);
impl<P, T> HttpNewService<P, T>
where
T: NewService<Request = ServiceRequest<P>, Response = ServiceResponse, Error = ()>,
T::Future: 'static,
<T::Service as Service>::Future: 'static,
{
pub fn new(service: T) -> Self {
HttpNewService(service)
}
}
impl<P: 'static, T> NewService for HttpNewService<P, T>
where
T: NewService<Request = ServiceRequest<P>, Response = ServiceResponse, Error = ()>,
T::Future: 'static,
T::Service: 'static,
<T::Service as Service>::Future: 'static,
{
type Request = ServiceRequest<P>;
type Response = ServiceResponse;
type Error = ();
type InitError = ();
type Service = BoxedHttpService<ServiceRequest<P>, Self::Response>;
type Future = Box<Future<Item = Self::Service, Error = Self::InitError>>;
fn new_service(&self, _: &()) -> Self::Future {