Browse Source

copy actix-web2

master
Nikolay Kim 1 year ago
parent
commit
2d7293aaf8
100 changed files with 6506 additions and 34921 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 {
Box::new(self.0.new_service(&()).map_err(|_| ()).and_then(|service| {
let service: BoxedHttpService<_, _> = Box::new(HttpServiceWrapper {
service,
_t: PhantomData,
});
Ok(service)
}))
}
}

struct HttpServiceWrapper<T: Service, P> {
service: T,
_t: PhantomData<(P,)>,
}

impl<T, P> Service for HttpServiceWrapper<T, P>
where
T::Future: 'static,
T: Service<Request = ServiceRequest<P>, Response = ServiceResponse, Error = ()>,
{
type Request = ServiceRequest<P>;
type Response = ServiceResponse;
type Error = ();
type Future = BoxedResponse;

fn poll_ready(&mut self) -> Poll<(), Self::Error> {
self.service.poll_ready().map_err(|_| ())
}

fn call(&mut self, req: ServiceRequest<P>) -> Self::Future {
Box::new(self.service.call(req))
}
}

#[doc(hidden)]
pub struct AppEntry<P> {
factory: Rc<RefCell<Option<AppFactory<P>>>>,
}

impl<P> AppEntry<P> {
fn new(factory: Rc<RefCell<Option<AppFactory<P>>>>) -> Self {
AppEntry { factory }
}
}

impl<P> NewService for AppEntry<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 {
self.factory.borrow_mut().as_mut().unwrap().new_service(&())
}
}

+ 169
- 263
src/application.rs View File

@@ -1,17 +1,21 @@
use std::rc::Rc;

use actix_http::http::ContentEncoding;
use actix_http::{Error, Request, Response};
use actix_service::Service;
use futures::{Async, Future, Poll};

use handler::{AsyncResult, FromRequest, Handler, Responder, WrapHandler};
use header::ContentEncoding;
use http::Method;
use httprequest::HttpRequest;
use httpresponse::HttpResponse;
use middleware::Middleware;
use pipeline::{Pipeline, PipelineHandler};
// use middleware::Middleware;
// use pipeline::{Pipeline, PipelineHandler};
use pred::Predicate;
use resource::Resource;
use router::{ResourceDef, Router};
use scope::Scope;
use server::{HttpHandler, HttpHandlerTask, IntoHttpHandler, Request};
// use scope::Scope;
// use server::{HttpHandler, HttpHandlerTask, IntoHttpHandler, Request};
use with::WithFactory;

/// Application
@@ -21,7 +25,7 @@ pub struct HttpApplication<S = ()> {
prefix_len: usize,
inner: Rc<Inner<S>>,
filters: Option<Vec<Box<Predicate<S>>>>,
middlewares: Rc<Vec<Box<Middleware<S>>>>,
// middlewares: Rc<Vec<Box<Middleware<S>>>>,
}

#[doc(hidden)]
@@ -30,16 +34,16 @@ pub struct Inner<S> {
encoding: ContentEncoding,
}

impl<S: 'static> PipelineHandler<S> for Inner<S> {
#[inline]
fn encoding(&self) -> ContentEncoding {
self.encoding
}
// impl<S: 'static> PipelineHandler<S> for Inner<S> {
// #[inline]
// fn encoding(&self) -> ContentEncoding {
// self.encoding
// }

fn handle(&self, req: &HttpRequest<S>) -> AsyncResult<HttpResponse> {
self.router.handle(req)
}
}
// fn handle(&self, req: &HttpRequest<S>) -> AsyncResult<HttpResponse> {
// self.router.handle(req)
// }
// }

impl<S: 'static> HttpApplication<S> {
#[cfg(test)]
@@ -54,10 +58,18 @@ impl<S: 'static> HttpApplication<S> {
}
}

impl<S: 'static> HttpHandler for HttpApplication<S> {
type Task = Pipeline<S, Inner<S>>;
impl<S: 'static> Service for HttpApplication<S> {
// type Task = Pipeline<S, Inner<S>>;
type Request = actix_http::Request;
type Response = actix_http::Response;
type Error = Error;
type Future = Box<Future<Item = Response, Error = Error>>;

fn handle(&self, msg: Request) -> Result<Pipeline<S, Inner<S>>, Request> {
fn poll_ready(&mut self) -> Poll<(), Self::Error> {
Ok(Async::Ready(()))
}

fn call(&mut self, msg: actix_http::Request) -> Self::Future {
let m = {
if self.prefix_len == 0 {
true
@@ -70,11 +82,12 @@ impl<S: 'static> HttpHandler for HttpApplication<S> {
};
if m {
if let Some(ref filters) = self.filters {
for filter in filters {
if !filter.check(&msg, &self.state) {
return Err(msg);
}
}
//for filter in filters {
// if !filter.check(&msg, &self.state) {
//return Err(msg);
unimplemented!()
// }
//}
}

let info = self
@@ -83,10 +96,12 @@ impl<S: 'static> HttpHandler for HttpApplication<S> {
.recognize(&msg, &self.state, self.prefix_len);

let inner = Rc::clone(&self.inner);
let req = HttpRequest::new(msg, Rc::clone(&self.state), info);
Ok(Pipeline::new(req, Rc::clone(&self.middlewares), inner))
// let req = HttpRequest::new(msg, Rc::clone(&self.state), info);
// Ok(Pipeline::new(req, inner))
unimplemented!()
} else {
Err(msg)
// Err(msg)
unimplemented!()
}
}
}
@@ -96,7 +111,7 @@ struct ApplicationParts<S> {
prefix: String,
router: Router<S>,
encoding: ContentEncoding,
middlewares: Vec<Box<Middleware<S>>>,
// middlewares: Vec<Box<Middleware<S>>>,
filters: Vec<Box<Predicate<S>>>,
}

@@ -106,55 +121,10 @@ pub struct App<S = ()> {
parts: Option<ApplicationParts<S>>,
}

impl App<()> {
/// Create application with empty state. Application can
/// be configured with a builder-like pattern.
pub fn new() -> App<()> {
App::with_state(())
}
}

impl Default for App<()> {
fn default() -> Self {
App::new()
}
}

impl<S> App<S>
where
S: 'static,
{
/// 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 with_state(state: S) -> App<S> {
App {
parts: Some(ApplicationParts {
state,
prefix: "".to_owned(),
router: Router::new(ResourceDef::prefix("")),
middlewares: Vec::new(),
filters: Vec::new(),
encoding: ContentEncoding::Auto,
}),
}
}

/// Get reference to the application state
pub fn state(&self) -> &S {
let parts = self.parts.as_ref().expect("Use after finish");
&parts.state
}

/// Set application prefix.
///
/// Only requests that match the application's prefix get
@@ -205,26 +175,6 @@ where
self
}

/// Add match predicate to application.
///
/// ```rust
/// # extern crate actix_web;
/// # use actix_web::*;
/// # fn main() {
/// App::new()
/// .filter(pred::Host("www.rust-lang.org"))
/// .resource("/path", |r| r.f(|_| HttpResponse::Ok()))
/// # .finish();
/// # }
/// ```
pub fn filter<T: Predicate<S> + 'static>(mut self, p: T) -> App<S> {
{
let parts = self.parts.as_mut().expect("Use after finish");
parts.filters.push(Box::new(p));
}
self
}

/// Configure route for a specific path.
///
/// This is a simplified version of the `App::resource()` method.
@@ -263,42 +213,42 @@ where
self
}

/// Configure scope for common root path.
///
/// Scopes collect multiple paths under a common path prefix.
/// Scope path can contain variable path segments as resources.
///
/// ```rust
/// # extern crate actix_web;
/// use actix_web::{http, App, HttpRequest, HttpResponse};
///
/// fn main() {
/// let app = App::new().scope("/{project_id}", |scope| {
/// scope
/// .resource("/path1", |r| r.f(|_| HttpResponse::Ok()))
/// .resource("/path2", |r| r.f(|_| HttpResponse::Ok()))
/// .resource("/path3", |r| r.f(|_| HttpResponse::MethodNotAllowed()))
/// });
/// }
/// ```
///
/// In the above example, three routes get added:
/// * /{project_id}/path1
/// * /{project_id}/path2
/// * /{project_id}/path3
///
pub fn scope<F>(mut self, path: &str, f: F) -> App<S>
where
F: FnOnce(Scope<S>) -> Scope<S>,
{
let scope = f(Scope::new(path));
self.parts
.as_mut()
.expect("Use after finish")
.router
.register_scope(scope);
self
}
// /// Configure scope for common root path.
// ///
// /// Scopes collect multiple paths under a common path prefix.
// /// Scope path can contain variable path segments as resources.
// ///
// /// ```rust
// /// # extern crate actix_web;
// /// use actix_web::{http, App, HttpRequest, HttpResponse};
// ///
// /// fn main() {
// /// let app = App::new().scope("/{project_id}", |scope| {
// /// scope
// /// .resource("/path1", |r| r.f(|_| HttpResponse::Ok()))
// /// .resource("/path2", |r| r.f(|_| HttpResponse::Ok()))
// /// .resource("/path3", |r| r.f(|_| HttpResponse::MethodNotAllowed()))
// /// });
// /// }
// /// ```
// ///
// /// In the above example, three routes get added:
// /// * /{project_id}/path1
// /// * /{project_id}/path2
// /// * /{project_id}/path3
// ///
// pub fn scope<F>(mut self, path: &str, f: F) -> App<S>
// where
// F: FnOnce(Scope<S>) -> Scope<S>,
// {
// let scope = f(Scope::new(path));
// self.parts
// .as_mut()
// .expect("Use after finish")
// .router
// .register_scope(scope);
// self
// }

/// Configure resource for a specific path.
///
@@ -377,51 +327,6 @@ where