1
0
mirror of https://github.com/fafhrd91/actix-web synced 2025-07-04 01:51:30 +02:00

Compare commits

...

1077 Commits

Author SHA1 Message Date
c5b18c6d30 prepare release 2018-04-12 16:03:22 -07:00
94c5bb5cdd add helper method for returning inner value 2018-04-12 15:55:15 -07:00
2ca0ea70c4 use one default cpu pool for StaticFiles #174 2018-04-12 15:50:20 -07:00
0b01884fca add timeouts stats to client connector 2018-04-12 13:08:13 -07:00
83168731fc update user guide content compression section 2018-04-12 09:54:35 -07:00
7295846426 Merge pull request #173 from jannic/pr
fix end-of-stream handling in parse_payload
2018-04-12 09:30:26 -07:00
72bc1546c4 fix end-of-stream handling in parse_payload
parse_payload can be called with a pre-filled buf.

In this case, it's totaly fine for read_from_io to return
sync::Ready(0) while buf is not empty. This is not an
PayloadError::Incomplete.

So, move the check for PayloadError::Incomplete down to the
decoding code: If the decoder is not ready, but the input stream
is finished, PayloadError::Incomplete will be returned.
2018-04-12 09:47:32 +02:00
d39b531537 Merge branch 'master' of github.com:actix/actix-web 2018-04-11 19:05:34 -07:00
35e68723df use older mdbook 2018-04-11 19:05:14 -07:00
0624f9b9d9 Update MIGRATION-0.4-0.5.md 2018-04-11 16:53:27 -07:00
0e3820afdf Update MIGRATION-0.4-0.5.md 2018-04-11 16:49:45 -07:00
839d67ac6a migration to 0.5 2018-04-11 16:46:21 -07:00
b517957761 fix stats for tls and alpn features 2018-04-11 16:34:01 -07:00
d18f9c5905 add clinet connector stats 2018-04-11 16:11:11 -07:00
76fcdc13a3 Merge pull request #171 from DoumanAsh/without_state_public
Make HttpRequest::without_state public
2018-04-11 23:48:19 +03:00
62a9b4c53c Rename HttpRequest::without_state into drop_state and make it public 2018-04-11 22:41:06 +03:00
c570229351 Update README.md 2018-04-11 10:49:34 -07:00
d041df6c4b update links 2018-04-10 19:27:09 -07:00
bc28e54976 add homepage link 2018-04-10 19:20:21 -07:00
26ab5cbd01 forgot to include 2018-04-10 15:14:46 -07:00
50c2a5ceb0 update basic example 2018-04-10 14:45:03 -07:00
8dbbb0ee07 update guide 2018-04-10 13:31:10 -07:00
ca76dff5a7 update redis example 2018-04-10 13:21:54 -07:00
88f66d49d0 openssl features 2018-04-10 11:07:54 -07:00
be288fa00a for NamedFile process etag and last modified only if status code is 200 2018-04-10 10:57:53 -07:00
5e6a0aa3df simplier example in readme 2018-04-10 10:39:16 -07:00
fd87eb59f8 remove reference to master 2018-04-10 10:29:10 -07:00
81ac905c7b fix prefix and static file serving #168 2018-04-10 10:16:00 -07:00
bb11fb3d24 update client mod doc string 2018-04-09 21:57:40 -07:00
23eea54776 update cors doc string 2018-04-09 21:39:32 -07:00
2881859400 proper test for CorsBuilder::resource 2018-04-09 21:29:57 -07:00
1686682c19 extend CorsBuilder api to make it more user friendly 2018-04-09 21:11:15 -07:00
d04ff13955 update version 2018-04-09 14:27:13 -07:00
e757dc5a71 clippy warnings 2018-04-09 14:25:30 -07:00
be358db422 CorsBuilder::finish() panics on any configuration error 2018-04-09 14:20:12 -07:00
7df2d6b12a clippy warnings; extend url_for example in user guide 2018-04-09 13:30:38 -07:00
458e6bdcc2 Merge pull request #170 from adwhit/private-cookies
Public, signed and private cookies
2018-04-09 12:54:15 -07:00
0b0bbd6bd9 Merge branch 'master' into private-cookies 2018-04-09 12:54:08 -07:00
5617896780 cleanup doc tests 2018-04-09 10:40:12 -07:00
2b803f30c9 remove CookieSessionBackend::new 2018-04-09 18:33:29 +01:00
9b152acc32 add signed and private cookies 2018-04-09 17:59:28 +01:00
eb66685d1a simplify csrf middleware 2018-04-09 09:49:07 -07:00
b505e682d4 fix session doc test 2018-04-09 09:31:11 -07:00
48e7013997 update guide examples 2018-04-09 07:57:50 -07:00
ff14633b3d simplify CookieSessionBackend; expose max_age cookie setting 2018-04-08 11:05:37 -07:00
37db7d8168 allow to override status code for NamedFile 2018-04-08 10:53:58 -07:00
89bf12605d Merge pull request #165 from tazjin/docs/various-doc-fixes
Various minor documentation fixes
2018-04-07 09:53:19 -07:00
9fb0498437 docs(lib): Add a note about getting started with the API docs
Adds some initial pointers for newcomers to the documentation that
direct them at some of the most commonly used API types.

I based these links on what *I* usually end up looking at when I open
the actix_web docs.
2018-04-07 17:27:53 +02:00
b2a43a3c8d docs(application): Formatting & spelling fixes in module docs 2018-04-07 17:19:11 +02:00
38063b9873 docs(client): Minor formatting and spelling fixes in module docs 2018-04-07 17:00:57 +02:00
1045a6c6f0 docs(README): Minor formatting and spelling fixes 2018-04-07 17:00:39 +02:00
7243c58fce stable rust compatibility 2018-04-06 21:57:45 -07:00
fffaf2bb2d App::route method 2018-04-06 21:18:42 -07:00
7becb95a97 fix guide example 2018-04-06 20:24:49 -07:00
a4b837a1c1 flaky test 2018-04-06 19:45:14 -07:00
542315ce7f simplify StaticFiles 2018-04-06 19:34:55 -07:00
602d78b76c Merge pull request #163 from memoryruins/guide
Guide: edits to the second half
2018-04-06 19:11:12 -07:00
18b706d4fb Guide: tweak to websocket and testing. 2018-04-06 19:44:52 -04:00
94b41fd484 Guide: tweak to database integration. 2018-04-06 19:42:18 -04:00
3a80cb7bf3 Guide: tweak to http/2. 2018-04-06 19:37:14 -04:00
e4a85a53f4 Guide: additional tweaks to Middleware. 2018-04-06 19:35:11 -04:00
1a45dbd768 Guide: additional tweak to testing chapter. 2018-04-06 19:26:07 -04:00
7cff5d9ade Guide: additional tweaks to request and response chapter. 2018-04-06 19:17:03 -04:00
c04e0fdec4 Merge branch 'master' into guide 2018-04-06 19:04:50 -04:00
0f0fe5f148 Guide: updates to the Database integration chapter. 2018-04-06 19:02:11 -04:00
e7f9f5b46d Guide: updates to HTTP/2 chapter. 2018-04-06 18:46:56 -04:00
c3fbba2678 Guide: updates to static file handling chapter. 2018-04-06 18:40:57 -04:00
a88e97edba Guide: updates to Middleware chapter. 2018-04-06 18:29:18 -04:00
1f08100f6f Guide: updates to the WebSockets chapter. 2018-04-06 18:04:42 -04:00
ab60ec6e1d Guide: updates to the Testing chapter. 2018-04-06 18:03:30 -04:00
0fbd05009d Guide: tweaks to the request and response chapter. 2018-04-06 17:31:18 -04:00
fdb7419e24 use actix-web from master 2018-04-06 14:11:04 -07:00
191b53bd7c pin futures 0.1 2018-04-06 13:22:27 -07:00
2d4ee0ee01 make Pause::new public 2018-04-06 12:34:24 -07:00
5bd5f67d79 add Pause message constructors 2018-04-06 12:31:31 -07:00
5d8cbccfe9 Remove article. 2018-04-06 15:12:06 -04:00
8d5fa6ee71 added Pause/Resume for client connector 2018-04-06 11:08:41 -07:00
084104d058 update doc strings for extractors 2018-04-06 10:24:57 -07:00
2c411a04a9 no need for export in doc example 2018-04-06 10:15:06 -07:00
af0c8d893d add shortcut method for client requests 2018-04-06 10:09:31 -07:00
691457fbfe update tests 2018-04-06 09:45:10 -07:00
2dafd9c681 do not re-export HttpServer from server module 2018-04-06 08:40:11 -07:00
12586db15c Merge pull request #160 from memoryruins/guide
Guide: edits to first half
2018-04-05 19:44:42 -07:00
b847bda8ca Merge branch 'master' into guide 2018-04-05 19:44:34 -07:00
2a543001e0 Tweaks to the URL Dispatch chapter. 2018-04-05 22:12:20 -04:00
0f86c596fa Tweaks to Errors chapter. 2018-04-05 21:54:39 -04:00
6c55501252 client connector wait timeout 2018-04-05 18:33:58 -07:00
961edfd21a Tweaks to the Handler chapter. 2018-04-05 21:30:52 -04:00
7f0de705a3 Tweaks to Server chapter. 2018-04-05 20:55:19 -04:00
c2ad65a61d Various tweaks to Application chapter. 2018-04-05 19:43:17 -04:00
3c93e0c654 Add newline for reading source. 2018-04-05 19:25:41 -04:00
a0f1ff7eb3 Add src directory to main.rs and list on first codeblock. 2018-04-05 19:21:29 -04:00
9f45cfe492 Expand note about actix. 2018-04-05 19:12:23 -04:00
46e6641528 Add repository hyperlink and trim repeat. 2018-04-05 18:46:36 -04:00
a3f124685a Remove redundant quickstart paragraph. 2018-04-05 18:32:04 -04:00
800f711cc1 add PayloadConfig 2018-04-04 21:13:48 -07:00
7be4b1f399 clippy warns 2018-04-04 20:24:09 -07:00
eeae0ddab4 start client timeout for response only 2018-04-04 20:15:47 -07:00
c1af59c618 update juniper example 2018-04-04 17:57:02 -07:00
d8a9606162 add connection limits to pool 2018-04-04 16:39:01 -07:00
8038a52287 run test coverage on beta 2018-04-04 08:12:33 -07:00
c273b7ac3f update json example 2018-04-04 08:08:31 -07:00
df21892b5b added extractor configuration 2018-04-03 22:06:18 -07:00
a255a6fb69 use build_response method 2018-04-03 17:37:17 -07:00
b693d5491b Merge pull request #157 from krircc/master
only use diesel::r2d2 feature. no need r2d2_diesel create
2018-04-03 08:18:16 -07:00
56a31ea0ee only use diesel::r2d2 feature. no need r2d2_diesel create 2018-04-03 22:37:53 +08:00
2a269f1111 update changes 2018-04-02 22:08:04 -07:00
fee30d6f47 fix doc test compatibility 2018-04-02 22:01:20 -07:00
476b1fb36a simplify DefaultHeaders middleware 2018-04-02 21:43:50 -07:00
3b93bff602 add ErrorHandlers middleware 2018-04-02 21:37:00 -07:00
d292c5023f add String and Bytes extractor 2018-04-02 16:19:18 -07:00
ef6f310060 update urlencoded example in guide 2018-04-02 15:08:49 -07:00
a6cbdde43f add extractor for Binary type; move all extractors to separate module 2018-04-02 14:55:42 -07:00
cbf4c61eb5 add urlencoded body extractor 2018-04-02 14:00:18 -07:00
280c8d87f8 expose ResourceType 2018-04-02 11:18:31 -07:00
83bf852192 Fix logger request duration calculation 2018-04-02 11:09:24 -07:00
9d39f441e9 Merge pull request #153 from rofrol/add-header-for-juniper-example
Add header for juniper example
2018-04-02 10:51:42 -07:00
03d851680b Merge branch 'master' into add-header-for-juniper-example 2018-04-02 10:51:35 -07:00
0ddd018214 Merge pull request #154 from dholbert/patch-1
Use https (not http) url for meritbadge
2018-04-02 10:50:17 -07:00
8219a7aebe Use https (not http) url for meritbadge
Right now this readme file uses an HTTP url to reference a meritbadge image, which ends up producing "broken https" UI on the crates.io page https://crates.io/crates/actix-web. This patch just upgrades this to an HTTPS url (which still works), to avoid that problem. (Literally a 1-character change, changing "http" to "https" in "http://meritbadge.herokuapp.com/actix-web")
2018-04-02 10:44:46 -07:00
6c906b08e1 match resource path before executing middlewares 2018-04-02 10:27:37 -07:00
220cbe40e5 Add header for juniper example 2018-04-02 19:10:33 +02:00
74d0656d27 update diesel example 2018-04-01 18:24:07 -07:00
17c27ef42d HttpRequest::resource() returns current matched resource 2018-04-01 17:37:22 -07:00
b2e771df2c use r2d2 for diesel example 2018-04-01 08:20:15 -07:00
a5a36ff194 update readme example 2018-03-31 17:15:44 -07:00
97e2bcd055 allow primitive types for Path extractor 2018-03-31 17:12:08 -07:00
23cfa649f4 update tests 2018-03-31 10:21:54 -07:00
8791c0f880 simplify With handlers 2018-03-31 09:58:33 -07:00
16c212f853 add extractors info to guide 2018-03-31 09:18:25 -07:00
3ee228005d rename Application 2018-03-31 00:16:55 -07:00
7a743fa6b5 update examples 2018-03-30 23:37:15 -07:00
44e3df82f6 simplify http response construction; deprecate httpcodes 2018-03-30 23:07:33 -07:00
8d8f6bedad update examples 2018-03-30 18:54:38 -07:00
9e751de707 re-arrange modules and exports 2018-03-30 17:31:18 -07:00
b16419348e add from HttpRequest to a HttpRequestBuilder 2018-03-30 14:30:24 -07:00
3ccaa04575 unhide AsyncResponder; remove unused code 2018-03-30 09:34:03 -07:00
d80b84c915 add test builder guide information 2018-03-29 19:23:45 -07:00
145010a2b0 use unreachable instead of panic 2018-03-29 15:55:27 -07:00
3e98177fad added State extractor 2018-03-29 15:41:13 -07:00
d24752d9bc update example in readme 2018-03-29 15:07:12 -07:00
92fe2e96de update doc strings 2018-03-29 15:00:18 -07:00
3cf54bc0fd proper serde deserializer implementation for path 2018-03-29 14:30:45 -07:00
86dd732704 use FromRequest instead of HttpRequestExtractor 2018-03-29 13:12:28 -07:00
dfd8f1058e move NormalizePath type to separate module 2018-03-29 11:39:21 -07:00
f5636f321b drop deprecated code 2018-03-29 11:06:44 -07:00
ae6c9cb7fa re-arrange exports, some doc string updates 2018-03-29 10:44:26 -07:00
32052c2750 update guide 2018-03-29 10:01:07 -07:00
7d6deab9fb drop request's extract_xxx methods 2018-03-29 09:26:01 -07:00
9e61c67128 do not re-export Version 2018-03-28 22:00:36 -07:00
13bb5f20d2 fix export name 2018-03-28 21:58:08 -07:00
d14991ec96 update doc strings 2018-03-28 21:49:50 -07:00
45dec8d0c0 optimize with and with2 method impls and tests 2018-03-28 21:33:40 -07:00
90e3aaaf8a fix router cannot parse Non-ASCII characters in URL #137 2018-03-28 16:10:58 -07:00
4f7d45ee9c remove unneeded import 2018-03-28 14:38:01 -07:00
e1d2536d85 remove unused code 2018-03-28 14:34:17 -07:00
65700281e8 add support for multiple extractors 2018-03-28 14:24:32 -07:00
80f6b93714 Merge pull request #138 from bwasty/guide
Guide: improve wording & style
2018-03-28 13:40:05 -07:00
5585465859 Merge branch 'master' into guide 2018-03-28 13:39:59 -07:00
368103dd09 guide: improve wording & style 2018-03-28 22:16:01 +02:00
df7ffe14f2 add PathAndQuery extractor 2018-03-28 11:20:06 -07:00
36161aba99 update Path and Query doc strings 2018-03-28 07:27:06 -07:00
9f5a91ae3c export types 2018-03-27 21:59:55 -07:00
4e61e0db34 mdbook 2018-03-27 21:33:35 -07:00
2dfccdd924 allow to fail nightly 2018-03-27 20:57:02 -07:00
4358da9926 refactor WithHandler trait 2018-03-27 20:33:24 -07:00
62fb75ff95 add Application::configure method, it simplifies configuration process 2018-03-27 11:16:02 -07:00
29a0feb415 fix guide example 2018-03-27 07:47:29 -07:00
dcc5eb7ace pass request as value 2018-03-26 23:34:31 -07:00
81f4e12a27 fix doc string test 2018-03-26 23:29:53 -07:00
2f60a4b89d add handler with exatractor 2018-03-26 23:10:31 -07:00
b03c7051ff add extractor info to the guide 2018-03-26 18:35:08 -07:00
8fff2c7595 remove Path and Query from public api 2018-03-26 18:18:38 -07:00
052d5f0bc5 silence AsciiExt deprecation warn 2018-03-26 16:12:25 -07:00
68cf32e848 add path and query extractors 2018-03-26 15:58:30 -07:00
a56e5113ee process transfer-encoding before content-length, fix tests on 32bit platform 2018-03-24 09:22:34 -07:00
5127b85672 Merge pull request #132 from andreevlex/spell-check-24-03
spelling check
2018-03-24 11:47:11 +03:00
2d80c5053d spelling check 2018-03-24 09:35:52 +03:00
d46854b315 bump version 2018-03-22 21:16:42 -07:00
47f836cd1b add helper method for response creation 2018-03-22 21:14:57 -07:00
449709dd7e add 0.5 sec deley before exit 2018-03-22 18:41:02 -07:00
5a25fd95f5 Fix panic on invalid URL characters #130 2018-03-22 18:08:12 -07:00
b942bcc4a6 Fix long client urls #129 2018-03-22 07:44:16 -07:00
1107fdec9d fix guide 2018-03-21 21:02:57 -07:00
04515e4697 update guide 2018-03-21 21:02:04 -07:00
93d99b5a49 Use more ergonomic actix_web::Error instead of http::Error for ClientRequestBuilder::body() 2018-03-21 20:19:31 -07:00
e49910cdab Use more ergonomic actix_web::Error instead of http::Error for HttpResponseBuilder::body() 2018-03-21 20:15:52 -07:00
e8a1850c79 add helper conversion from ClientResponse for HttpResponseBuilder 2018-03-21 20:04:35 -07:00
afb81b6b8f add convinience ClientRequest::build_from() from HttpRequest 2018-03-21 19:54:21 -07:00
4866a26578 make streaming method more ergonomic 2018-03-21 19:14:18 -07:00
2d75ced4ed fix client connection pooling 2018-03-21 11:51:08 -07:00
7bcc258b09 Use fast compression setting 2018-03-21 08:56:21 -07:00
d5fa0a9418 disable brotli if feature is not enabled, faster compression 2018-03-21 08:03:21 -07:00
ce6d237cc1 prepare 0.4.10 release 2018-03-20 15:53:39 -07:00
70caa2552b simplify httpresponse release 2018-03-20 15:51:19 -07:00
ee7d58dd7f disable h2 2018-03-20 12:35:44 -07:00
c4f4cadb43 Fix http/2 date header generation 2018-03-20 11:40:05 -07:00
978091cedb wake up io task when next chunk of data is needed 2018-03-20 11:37:13 -07:00
8198f5e10a Refactor TestServer configuration 2018-03-20 11:23:35 -07:00
6cd40df387 Fix server websockets big payloads support 2018-03-19 17:27:03 -07:00
35ee5d36d8 actix 0.5.5, ws test 2018-03-19 13:12:36 -07:00
e7ec0f9fd7 ws tests and proper write payload ref 2018-03-19 09:30:58 -07:00
f4a47ef71e allow set client request/ws timeout 2018-03-18 19:27:51 -07:00
6b1a79fab8 update example 2018-03-18 16:27:34 -07:00
ab73da4a1a use Error instead of InternalError for helper methods error::ErrorXXX 2018-03-18 14:18:47 -07:00
e0c8da567c various optimizations 2018-03-18 11:05:44 -07:00
c10dedf7e4 Merge pull request #124 from DoumanAsh/show_hidden
Show Request's hidden methods
2018-03-17 18:39:21 +03:00
ec192e0ab1 Show Request's hidden methods 2018-03-17 18:10:22 +03:00
6d792d9948 simplify h1 parse 2018-03-16 20:56:23 -07:00
1fe4315c94 use actix 0.5.4 2018-03-16 13:37:47 -07:00
381b90e9a1 bump version 2018-03-16 12:31:29 -07:00
2d18dba40a fix compilation 2018-03-16 12:28:08 -07:00
d2693d58a8 clippy warnings 2018-03-16 12:12:55 -07:00
84bf282c17 add basic client connection pooling 2018-03-16 12:04:01 -07:00
b15b5e5246 check number of available workers 2018-03-16 11:17:27 -07:00
52b3b0c362 Merge pull request #119 from DoumanAsh/default_static_files
Add default resource for StaticFiles
2018-03-16 20:12:07 +03:00
64c4cefa8f Merge branch 'master' into default_static_files 2018-03-16 09:31:36 -07:00
7e8b231f57 disable test 2018-03-16 09:13:36 -07:00
8a344d0c94 Add default resource for StaticFiles 2018-03-16 19:04:36 +03:00
4096089a3f allow to disable http/2 support 2018-03-16 08:48:44 -07:00
b16f2d5f05 proper check for actor context poll 2018-03-16 08:04:26 -07:00
5baf15822a always start actors 2018-03-16 07:46:27 -07:00
5368ce823e Merge pull request #123 from h416/patch-1
fix typo
2018-03-16 05:31:10 -07:00
4effdf065b fix typo 2018-03-16 19:03:16 +09:00
61970ab190 always poll stream or actor for the first time 2018-03-15 17:11:49 -07:00
484b00a0f9 Merge branch 'master' of github.com:actix/actix-web 2018-03-15 16:55:33 -07:00
73bf2068aa allow to use NamedFile with any request method 2018-03-15 16:55:22 -07:00
1cda949204 Merge pull request #122 from mockersf/test_qp
test for query parameters in client
2018-03-14 16:10:31 -07:00
ad6b823255 test for query parameters in client 2018-03-14 21:45:49 +01:00
0f064db31d Move brotli encoding to a feature 2018-03-13 17:21:22 -07:00
fd0bb54469 add debug formatter for ClientRequestBuilder 2018-03-13 15:09:05 -07:00
e27bbaa55c Update CHANGES.md 2018-03-13 13:15:21 -07:00
8a50eae1e2 Merge pull request #121 from glademiller/master
Send Query Parameters in client requests
2018-03-13 13:14:51 -07:00
38080f67b3 If no path is available from the URI request / 2018-03-13 13:35:11 -06:00
08504e0892 Move path call inline into write 2018-03-13 13:26:13 -06:00
401c0ad809 https://github.com/actix/actix-web/issues/120 - Send Query Parameters in client requests 2018-03-13 13:17:55 -06:00
b4b0deb7fa Wake payload reading task when data is available 2018-03-12 16:29:13 -07:00
05ff35d383 Fix server keep-alive handling 2018-03-12 16:16:17 -07:00
29c3e8f7ea update test 2018-03-12 10:19:09 -07:00
6657446433 Allow to set read buffer capacity for server request 2018-03-12 10:01:56 -07:00
46b9a9c887 update readme 2018-03-12 09:13:04 -07:00
b3cdb472d0 remove reserved state for h2 write if buffer is empty 2018-03-12 09:04:54 -07:00
31e1aab9a4 do not log WouldBlock error from socket accept 2018-03-12 09:02:15 -07:00
67f383f346 typo 2018-03-11 16:53:46 -07:00
49f5c335f6 better sleep on error 2018-03-11 16:52:20 -07:00
692e11a584 bump version 2018-03-11 16:40:25 -07:00
208117ca6f Merge pull request #118 from messense/feature/sockets-vec
Use Vec instead of HashMap to store sockets in HttpServer
2018-03-11 16:38:23 -07:00
3e276ac921 Merge branch 'master' into feature/sockets-vec 2018-03-11 16:38:17 -07:00
4af115a19c Fix steraming response handling for http/2 2018-03-11 16:37:44 -07:00
051703eb2c Fix connection get closed too early 2018-03-11 15:37:33 -07:00
31fbbd3168 Fix panic on unknown content encoding 2018-03-11 14:50:13 -07:00
fee1e255ac add comments 2018-03-11 10:10:30 -07:00
a4c933e56e update doc string 2018-03-11 09:36:54 -07:00
9ddf5a3550 better doc string for Either 2018-03-11 09:28:22 -07:00
9ab0fa604d Use Vec instead of HashMap to store sockets in HttpServer 2018-03-11 17:29:44 +08:00
6c709b33cc return error on write zero bytes 2018-03-10 10:42:46 -08:00
71b4c07ea4 Fix json content type detection 2018-03-10 10:27:29 -08:00
ac9eba8261 add api doc for Either 2018-03-10 10:12:44 -08:00
cad55f9c80 add Either responder 2018-03-10 09:39:43 -08:00
4263574a58 fix panic in cors if request does not contain origin header and send_wildcard is not set 2018-03-10 08:31:20 -08:00
84ef5ee410 Merge pull request #116 from messense/feature/from-usize-to-keepalive
Impl From<usize> and From<Option<usize>> for KeepAlive
2018-03-10 22:55:55 +08:00
598fb9190d rerun build if USE_SKEPTIC env var changed 2018-03-10 17:53:11 +08:00
9a404a0c03 Impl From<usize> and From<Option<usize>> for KeepAlive 2018-03-10 17:52:50 +08:00
3dd8fdf450 fix guide 2018-03-09 21:40:51 -08:00
05f5ba0084 refactor keep-alive; fixed write to socket for upgraded connection 2018-03-09 16:21:14 -08:00
8169149554 update wstool 2018-03-09 13:12:25 -08:00
8d1de6c497 ws client timeouts 2018-03-09 13:12:14 -08:00
caaace82e3 export symbols 2018-03-09 13:03:15 -08:00
02dd5375a9 aling mask to 8 bytes 2018-03-09 10:25:47 -08:00
717602472a clippy warnings 2018-03-09 10:11:38 -08:00
b56be8e571 write buffer capacity for client 2018-03-09 10:09:13 -08:00
2853086463 add write buffer capacity config 2018-03-09 10:00:15 -08:00
e2107ec6f4 use small vec on hot path 2018-03-09 08:00:44 -08:00
c33caddf57 update tests 2018-03-09 05:50:47 -08:00
db1e04e418 prepare release 2018-03-09 05:42:42 -08:00
f8b8fe3865 add space to cookie header 2018-03-09 05:38:07 -08:00
1c6ddfd34c naming 2018-03-09 05:36:40 -08:00
49e007ff2a move protobuf support to the example 2018-03-09 05:29:06 -08:00
2068eee669 update readme 2018-03-08 20:58:05 -08:00
f3c63e631a add protobuf feature 2018-03-08 20:56:18 -08:00
3f0803a7d3 Merge branch 'master' of github.com:actix/actix-web 2018-03-08 20:39:10 -08:00
f12b613211 more ws optimizations 2018-03-08 20:39:05 -08:00
695c052c58 Merge pull request #115 from kingxsp/master
Add protobuf support
2018-03-08 18:59:18 -08:00
63634be542 Merge branch 'master' into master 2018-03-09 10:22:15 +08:00
f88f1c65b6 update tests 2018-03-08 18:19:46 -08:00
a0b589eb96 Add protobuf support 2018-03-09 10:05:13 +08:00
ebdc983dfe optimize websocket stream 2018-03-08 17:19:50 -08:00
395243a539 another attempt to fix cookie handling 2018-03-08 11:16:54 -08:00
1ab676d7eb bump version and add some tests 2018-03-07 22:40:46 -08:00
47f01e5b7e update doc string 2018-03-07 21:39:20 -08:00
ffb89935b6 update all features 2018-03-07 21:37:42 -08:00
77a111b95c prepare release 2018-03-07 21:28:54 -08:00
6c0fb3a7d2 handle panics in worker threads 2018-03-07 21:10:53 -08:00
824244622f update test 2018-03-07 17:42:57 -08:00
42d2a29b1d non-blocking processing for NamedFile 2018-03-07 17:40:13 -08:00
af8875f6ab sleep on accept socket error 2018-03-07 15:52:05 -08:00
1db1ce1ca3 one more cookie handling fix 2018-03-07 15:41:46 -08:00
f55ef3a059 create default CpuPool 2018-03-07 14:56:53 -08:00
67bf0ae79f fix HttpServer::listen method 2018-03-07 14:46:12 -08:00
b06cf32329 Merge pull request #114 from DancingBard/master
BoyScoutRule: Fixed typo
2018-03-07 13:07:10 -08:00
7cce29b633 BoyScoutRule: Fixed typo 2018-03-07 21:54:25 +01:00
c26d9545a5 map connector timeout error 2018-03-07 12:09:53 -08:00
b950d6997d add csrf link to readme 2018-03-07 11:31:02 -08:00
0bf29a522b Allow to use std::net::TcpListener for HttpServer 2018-03-07 11:28:44 -08:00
24342fb745 Merge pull request #113 from niklasf/csrf-upgrade
Let CSRF filter catch cross-site upgrades
2018-03-07 09:58:30 -08:00
0278e364ec add tests for csrf upgrade filter 2018-03-07 18:42:21 +01:00
b9d6bbd357 filter cross-site upgrades in csrf middleware 2018-03-07 17:49:30 +01:00
5816ecd1bc fix variable name: cors -> csrf 2018-03-07 17:44:19 +01:00
2ff55ee1c5 Update CHANGES.md 2018-03-07 06:14:44 -08:00
b42de6c41f Merge pull request #111 from adwhit/cookie-handling
Fix client cookie handling
2018-03-07 06:13:02 -08:00
9e0e081c90 Merge branch 'master' into cookie-handling 2018-03-07 06:12:37 -08:00
178f5a104e Merge pull request #110 from messense/feature/tools-actix
Use actix from crates.io in tools/wsload
2018-03-07 06:10:18 -08:00
1e42f9575a Merge branch 'master' into feature/tools-actix 2018-03-07 06:09:09 -08:00
24dfcf1303 Merge pull request #109 from kingoflolz/master
make session an optional feature
2018-03-07 06:04:55 -08:00
6cc3aaef1b add client cookie handling test 2018-03-07 11:43:55 +00:00
436a16a2c8 Use actix from crates.io in tools/wsload 2018-03-07 19:26:23 +08:00
9afad5885b fix client cookie handling 2018-03-07 09:48:34 +00:00
04d0abb3c7 make session an optional feature 2018-03-07 15:38:58 +08:00
1e5daa1de8 update changes 2018-03-06 23:04:18 -08:00
d3c859f9f3 bump version 2018-03-06 22:44:06 -08:00
c1419413aa Fix client cookie support 2018-03-06 22:36:34 -08:00
acd33cccbb add tls 2018-03-06 17:34:46 -08:00
57a1d68f89 add client response timeout 2018-03-06 17:04:48 -08:00
5c88441cd7 Merge pull request #108 from glademiller/feature/allow_connection_timeout_to_be_set
Allow connection timeout to be set
2018-03-06 15:18:31 -08:00
6a3c5c4ce0 Merge branch 'master' into feature/allow_connection_timeout_to_be_set 2018-03-06 15:18:25 -08:00
14a511bdad use IntoHeaderValue and Header for client request 2018-03-06 15:18:04 -08:00
e4ed53d691 Merge branch 'feature/allow_connection_timeout_to_be_set' of https://github.com/glademiller/actix-web into feature/allow_connection_timeout_to_be_set 2018-03-06 15:44:18 -07:00
5bf4f3be8b Actix dependency needs to be updated to master 2018-03-06 15:43:56 -07:00
6b9e51740b Merge branch 'master' into feature/allow_connection_timeout_to_be_set 2018-03-06 15:28:31 -07:00
be7e8d159b Allow connection timeout to be set 2018-03-06 15:26:09 -07:00
ceb97cd6b9 Merge pull request #106 from niklasf/starting-url
give a url in the log when starting
2018-03-06 11:41:42 -08:00
85b650048d give a url in the log when starting 2018-03-06 20:37:18 +01:00
a0e6313d56 Fix compression #103 and #104 2018-03-06 11:02:03 -08:00
9cc6f6b1e4 Merge pull request #102 from mockersf/gzip
add tests with large random bodies for gzip
2018-03-06 08:48:06 -08:00
526753ee88 update tests for stable compiler 2018-03-06 07:56:43 -08:00
779e773185 add tests with large random bodies for gzip 2018-03-06 14:26:48 +01:00
7eb310f8ce fix guide 2018-03-06 00:44:45 -08:00
d573cf2d97 Merge branch 'master' of github.com:actix/actix-web 2018-03-06 00:43:34 -08:00
32b5544ad9 port hyper header 2018-03-06 00:43:25 -08:00
e182ed33b1 add Header trait 2018-03-05 19:28:42 -08:00
6f1836f80e Merge pull request #98 from flip111/patch-2
Update qs_14.md
2018-03-05 16:48:47 -08:00
5b530f11b5 Update qs_14.md
fix missing semicolon
2018-03-06 01:46:16 +01:00
0c30057c8c move headers to separate module; allow custom HeaderValue conversion 2018-03-05 16:45:54 -08:00
6078344ecc Merge pull request #97 from flip111/patch-1
Update qs_14.md
2018-03-05 16:36:32 -08:00
67f5a949a4 Update qs_14.md
fix syntax error on use statement
2018-03-06 01:35:41 +01:00
05e49e893e allow only GET and HEAD for NamedFile 2018-03-05 14:04:30 -08:00
c8844425ad Enable compression support for NamedFile 2018-03-05 13:31:30 -08:00
b282ec106e Add ResponseError impl for SendRequestError 2018-03-05 13:02:31 -08:00
ea2a8f6908 add http proxy example 2018-03-05 11:12:19 -08:00
2b942ec5f2 add uds example readme 2018-03-05 09:47:17 -08:00
bf77be0337 Merge pull request #95 from messense/feature/unix-socket-example
Add unix domain socket example
2018-03-05 09:37:00 -08:00
c2741054bb Add unix domain socket example 2018-03-05 22:14:25 +08:00
e708f51156 prep release 2018-03-04 20:28:06 -08:00
cbb821148b explicitly set tcp nodelay 2018-03-04 20:14:58 -08:00
d6b021e185 Merge pull request #94 from messense/feature/str-repeat
Use str::repeat
2018-03-04 19:57:49 -08:00
0adb7e8553 Use str::repeat 2018-03-05 09:54:58 +08:00
dbfa1f0ac8 fix example 2018-03-04 10:44:41 -08:00
11347e3c7d Allow to use Arc<Vec<u8>> as response/request body 2018-03-04 10:33:18 -08:00
631fe72a46 websockets text() is more generic 2018-03-04 10:18:42 -08:00
f673dba759 Fix handling of requests with an encoded body with a length > 8192 #93 2018-03-04 09:48:34 -08:00
ab978a18ff unix only test 2018-03-03 18:50:00 -08:00
327df159c6 prepare release 2018-03-03 18:46:22 -08:00
2ccbd5fa18 fix socket polling 2018-03-03 12:17:26 -08:00
058630d041 simplify channels list management 2018-03-03 11:16:55 -08:00
f456be0309 simplify linked nodes 2018-03-03 10:06:13 -08:00
9bd6cb03ac Merge branch 'master' of github.com:actix/actix-web 2018-03-03 09:29:46 -08:00
16afeda79c update changes 2018-03-03 09:29:36 -08:00
83fcdfd91f fix potential bug in payload processing 2018-03-03 09:27:54 -08:00
8f94ae41cc Merge pull request #90 from rvlzzr/master
move reuse_address before bind
2018-03-02 23:08:33 -08:00
4e41347de8 move reuse_address before bind 2018-03-02 22:57:11 -08:00
6acb6dd4e7 set release date 2018-03-02 22:31:58 -08:00
791a980e2d update tests 2018-03-02 22:08:56 -08:00
c2d8abcee7 Fix disconnect on idle connections 2018-03-02 20:47:23 -08:00
16c05f07ba make HttpRequest::match_info_mut() public 2018-03-02 20:40:08 -08:00
2158ad29ee add Pattern::with_prefix, make it usable outside of actix 2018-03-02 20:39:22 -08:00
feba5aeffd bump version 2018-03-02 14:31:23 -08:00
343888017e Update CHANGES.md 2018-03-02 12:26:31 -08:00
3a5d445b2f Merge pull request #89 from niklasf/csrf-middleware
add csrf filter middleware
2018-03-02 12:25:23 -08:00
e60acb7607 Merge branch 'master' into csrf-middleware 2018-03-02 12:25:05 -08:00
bebfc6c9b5 sleep for test 2018-03-02 11:32:37 -08:00
3b2928a391 Better naming for websockets implementation 2018-03-02 11:29:55 -08:00
10f57dac31 add csrf filter middleware 2018-03-02 20:13:43 +01:00
b640b49b05 adjust low buf size 2018-03-01 20:13:50 -08:00
1fea4bd9a6 prepare release 2018-03-01 20:01:25 -08:00
206c4e581a rename httpcodes 2018-03-01 19:12:59 -08:00
4e13505b92 rename .p to a .filter 2018-03-01 18:42:50 -08:00
5b6d7cddbf Fix payload parse in situation when socket data is not ready 2018-03-01 18:27:04 -08:00
4aaf9f08f8 update readme 2018-02-28 22:31:54 -08:00
b0ba23ff55 Merge pull request #88 from rofrol/patch-2
be consistent with host - had CORS preflight once
2018-02-28 17:07:57 -08:00
42b19b1819 Merge branch 'master' into patch-2 2018-02-28 17:07:44 -08:00
0335fde3f9 Update README.md 2018-02-28 16:58:05 -08:00
f27edbff89 be consistent with host - had CORS preflight once 2018-03-01 01:01:27 +01:00
d62d6e68e0 use new version of http crate 2018-02-28 14:16:55 -08:00
1284264511 Update CHANGES.md 2018-02-28 12:35:16 -08:00
d977fe563b Merge pull request #87 from adwhit/fix-session-set
fix session mut borrow lifetime
2018-02-28 12:34:46 -08:00
bb68f9dd90 add session borrow fix to changes 2018-02-28 19:52:53 +00:00
313396d9b5 fix session mut borrow lifetime 2018-02-28 19:35:26 +00:00
171a23561e export Drain 2018-02-28 11:10:54 -08:00
67f33a4760 add redis session example 2018-02-28 10:26:40 -08:00
764421fe44 update categories 2018-02-27 23:51:57 -08:00
b339ea0a3a update versions in guide 2018-02-27 23:31:43 -08:00
8994732227 doc strings 2018-02-27 23:30:26 -08:00
7591592279 fix handle big data chunkd for parsing 2018-02-27 23:04:57 -08:00
4a48b43927 big value 2018-02-27 21:49:08 -08:00
b1ad4763a2 check juniper example 2018-02-27 21:23:41 -08:00
2f3a2115c0 Merge pull request #86 from pyros2097/master
add juniper example
2018-02-27 21:21:52 -08:00
1283c00583 add juniper example 2018-02-28 10:41:24 +05:30
9f81eae215 build docs on nightly 2018-02-27 21:04:22 -08:00
ccb6ebb259 headers test 2018-02-27 20:49:53 -08:00
da76de76f0 upgrade sha crate 2018-02-27 20:32:51 -08:00
c316a99746 stop server test 2018-02-27 20:04:01 -08:00
1e2aa4fc90 mark context as modified after writing data 2018-02-27 18:05:06 -08:00
e2c8f17c2c drop connection if handler get dropped without consuming payload 2018-02-27 16:08:57 -08:00
9b06eac720 Merge branch 'master' of github.com:actix/actix-web 2018-02-27 15:41:53 -08:00
4f99cd1580 add ws error tracing 2018-02-27 15:38:57 -08:00
f56fa49a9b Merge pull request #84 from mpaltun/patch-1
Fix typos in README
2018-02-27 15:18:16 -08:00
1f063e4136 move with_connector method to ClientRequestBuilder 2018-02-27 15:14:33 -08:00
33c935dccc Fix typos in README 2018-02-28 01:13:59 +02:00
a7bf635158 unify headers and body processing for client response and server request 2018-02-27 15:03:28 -08:00
aac9b5a97c update readme 2018-02-27 12:49:11 -08:00
6c480fae90 added HttpRequest::encoding() method; fix urlencoded parsing with charset 2018-02-27 11:31:54 -08:00
5dcb558f50 refactor websockets handling 2018-02-27 10:09:24 -08:00
a344c3a02e remove read buffer management api 2018-02-26 20:07:22 -08:00
0ab8bc11f3 fix guide example 2018-02-26 16:41:57 -08:00
abae65a49e remove unused code 2018-02-26 16:11:00 -08:00
d6fd4a3524 use buffer capacity; remove unused imports 2018-02-26 15:34:25 -08:00
72aa2d9eae clippy warnings 2018-02-26 14:33:56 -08:00
644f1a9518 refactor ws frame parser 2018-02-26 13:58:23 -08:00
56ae565688 fix guide examples 2018-02-26 08:02:58 -08:00
0a3b776aa7 refactor multipart stream 2018-02-26 06:00:54 +03:00
6ef9c60361 add Read and AsyncRead impl to HttpRequest 2018-02-25 21:26:58 +03:00
a2b98b31e8 refactor payload related futures for HttpRequest 2018-02-25 20:34:26 +03:00
ab5ed27bf1 refactor and simplify content encoding 2018-02-25 11:43:00 +03:00
141b992450 Make payload and httprequest a stream 2018-02-25 11:21:45 +03:00
4e41e13baf refactor client payload processing 2018-02-25 11:18:17 +03:00
ea8e8e75a2 fix websocket example 2018-02-24 08:41:58 +03:00
a855c8b2c9 better ergonomics for WsClient::client() 2018-02-24 08:14:21 +03:00
fd31eb74c5 better ergonomics for ws client 2018-02-24 07:36:50 +03:00
3b22b1b168 Merge pull request #78 from pyros2097/master
Fix websocket example path
2018-02-23 01:47:40 -08:00
7a7df7f8fb Merge branch 'master' into master 2018-02-23 01:47:30 -08:00
25aabfb3e2 fix big ws frames 2018-02-23 10:45:33 +01:00
3a3657cfaf Update qs_9.md 2018-02-23 12:39:19 +05:30
aff43cc8b8 fix routes registration order 2018-02-22 05:48:18 -08:00
4a9c1ae894 allow to use Connection for sending client request 2018-02-21 22:53:23 -08:00
4a07430e8e remove RegexSet mention 2018-02-21 22:04:59 -08:00
9a076c69d1 update route matching guide section 2018-02-21 22:00:22 -08:00
8f2d3a0a76 fix NormalizePath helper 2018-02-21 14:53:42 -08:00
d4611f8bb9 Merge branch 'master' of github.com:actix/actix-web 2018-02-21 14:31:31 -08:00
fd56e5dc82 do not use regset for route recognition 2018-02-21 14:31:22 -08:00
7c74259453 Merge pull request #77 from rofrol/patch-1
could used -> could be used, latest actix sync
2018-02-21 10:00:08 -08:00
6a01af32bc could used -> could be used, latest actix sync 2018-02-21 18:59:00 +01:00
5634e5794f more tests for NormalizePath helper 2018-02-20 13:03:21 -08:00
187644e178 update logger doc string 2018-02-20 12:53:51 -08:00
7198dde465 add logger info 2018-02-20 12:49:42 -08:00
2374aa42ed set date header for client requests 2018-02-19 23:18:18 -08:00
03912d2089 support client request's async body 2018-02-19 22:48:27 -08:00
3f95cce9e8 allow to pass different binary data 2018-02-19 20:03:57 -08:00
979cea03ac added TestRequest::set_payload() 2018-02-19 20:01:38 -08:00
6424defee6 code coverage on 1.21 2018-02-19 17:32:22 -08:00
6ee14efbe2 optimize http message serialization 2018-02-19 17:21:04 -08:00
4d81186059 escape router pattern re 2018-02-19 14:57:57 -08:00
ddc82395e8 try to remove trailing slash for normalize path handler 2018-02-19 14:27:36 -08:00
360ffbba68 clone router with httprequest 2018-02-19 14:26:51 -08:00
f2f1798215 allow to send request using custom connector 2018-02-19 13:41:21 -08:00
548f4e4d62 replace reqwest with actix::client 2018-02-19 13:18:18 -08:00
cb70d5ec3d refactor http client 2018-02-19 03:11:11 -08:00
edd114f6e4 allow to set default content encoding on application level 2018-02-18 22:23:17 -08:00
816c6fb0e0 log 5xx responses as error 2018-02-18 09:57:57 -08:00
0da382a7a4 use actix 0.5 release 2018-02-17 13:33:38 -08:00
3e3d3279b8 deregister server socket on shutdown 2018-02-16 09:42:15 -08:00
3c95823e53 add r2d2 example 2018-02-15 23:05:10 -08:00
8607c51bcf do not stop accept thread on error 2018-02-15 22:02:03 -08:00
080bb3e5ae disable dead code link 2018-02-15 16:25:43 -08:00
d31e71a169 update examples 2018-02-15 13:59:25 -08:00
7b0e1642b6 add techempower benchmark link 2018-02-15 09:53:09 -08:00
096dee519c Merge pull request #71 from rbtcollins/patch-1
Wait for spawned thread
2018-02-13 14:58:11 -08:00
8bce3b9d10 Merge branch 'master' into patch-1 2018-02-13 14:57:59 -08:00
b28ecbcf0c Update qs_2.md 2018-02-14 10:37:12 +13:00
8f9ec5c23c fix doc test 2018-02-13 07:50:49 -08:00
96b87761d1 update examples 2018-02-12 23:13:06 -08:00
b1eec3131f use newer api 2018-02-12 22:56:47 -08:00
a544034c06 use Recipient 2018-02-12 22:09:31 -08:00
4b8181476c consistently use #[cause] and display causing errors (#73) 2018-02-12 23:55:44 -06:00
eb041de36d update examples 2018-02-12 19:15:39 -08:00
80285f2a32 fix doc test 2018-02-12 18:38:13 -08:00
de869ed879 Merge pull request #72 from rbtcollins/patch-2
Use AtomicUsize properly
2018-02-12 17:46:03 -08:00
7ccacb92ce update websocket-chat example 2018-02-12 17:42:10 -08:00
57655d8153 Use AtomicUsize properly
doing a read+write on an atomic int will lose updates from other threads.
2018-02-13 13:47:59 +13:00
335ca8ff33 use new actix api 2018-02-12 16:08:04 -08:00
720d8c36c1 update names 2018-02-12 12:45:08 -08:00
8c1b5fa945 sync with latest actix 2018-02-12 12:17:30 -08:00
232aba2080 Wait for spawned thread
A spawned thread doesn't block the main thread exiting unless explicitly joined.
The demo as written in the guide simply exits immediately at the moment.
2018-02-12 23:52:03 +13:00
30bdf9cb5e update actix api 2018-02-12 01:13:06 -08:00
285c66e7d8 build docs for apln and tls features 2018-02-10 11:39:12 -08:00
856055c6ca simplify HttpServer::start_tls() method 2018-02-10 11:34:54 -08:00
e3081306da update doc string 2018-02-10 11:29:40 -08:00
94c4053cb5 more HttpServer type simplification 2018-02-10 11:01:54 -08:00
762961b0f4 simplify HttpServer type definition 2018-02-10 10:22:03 -08:00
3109f9be62 special handling for upgraded pipeline 2018-02-10 00:05:20 -08:00
2d049e4a9f update example 2018-02-09 22:46:34 -08:00
0c98775b51 refactor h1 stream polling 2018-02-09 22:26:48 -08:00
b4b5c78b51 optimize ws frame generation 2018-02-09 20:43:14 -08:00
78da98a16d add wsload tool; optimize ws frame parser 2018-02-09 17:20:28 -08:00
74377ef73d fix back pressure for h1 import stream 2018-02-09 16:20:10 -08:00
728377a447 fix example 2018-02-08 20:55:34 -08:00
73ed1342eb more actix compatibility 2018-02-08 17:13:56 -08:00
bc6300be34 actix compatibility 2018-02-08 17:08:57 -08:00
2faf3a5eb6 fix deprecation warnings, update actix 2018-02-08 17:00:22 -08:00
6181a84d7b update websocket-chat example 2018-02-08 14:03:41 -08:00
f8f99ec0c7 Disable signals in HttpServers started by the tests. (#69)
Something is wrong with signals on windows.
This change causes the unit tests to pass on Windows.
2018-02-08 14:55:47 -06:00
bd03ba1192 Update most examples to use actix from git (#68) 2018-02-08 00:08:36 -06:00
d0cbf7cd25 upgrade trust-dns-resolver 2018-02-07 14:58:08 -08:00
93aa220e8d remove default impl for std error, it prevents use of Fail 2018-02-07 13:57:58 -08:00
81e4fb9353 Avoid using Path to calculate URIs, because it doesn't do the right thing on Windows (#67)
Redirecting to index files now always uses `/` instead of backslash on windows.
2018-02-07 15:31:09 -06:00
884ea02f5c Allow returning failure::Error from handlers (#65)
This implements From<failure::Error> for Error (by way of `failure::Compat`)
and ResponseError for failure::Compat<T>.
2018-02-06 10:26:50 -06:00
b6d5516e3a remove rust_backtrace for appveyor 2018-02-04 10:48:16 -08:00
46841cc87e update config for appveyor 2018-02-04 10:31:39 -08:00
7ad66956b2 add HttpRequest::uri_mut(), allows to modify request uri 2018-02-03 08:31:32 -08:00
d568161852 update websocket-chat example 2018-02-03 08:25:31 -08:00
671ab35cf6 re enable 1.21 2018-02-02 21:32:43 -08:00
c63ad4b6f1 appveyor cfg 2018-02-02 21:31:16 -08:00
eb713bd60e update actix version 2018-02-01 01:08:08 -08:00
2b74fbf586 fix websocket example 2018-01-31 13:18:30 -08:00
58f85658bd update actix 2018-01-31 12:57:02 -08:00
7e9fbfca72 missing http codes 2018-01-31 12:34:58 -08:00
5115384501 Merge pull request #64 from andreevlex/fix-2
spelling check
2018-01-31 10:54:05 -08:00
a1b96b1cf4 return "chnked" value 2018-01-31 21:37:12 +03:00
a565e71018 spelling check 2018-01-31 20:28:53 +03:00
e41b175e3d Update README.md 2018-01-31 06:40:00 -08:00
db39f122be Update README.md 2018-01-31 06:37:37 -08:00
afd2dc4666 Update README.md 2018-01-31 06:36:15 -08:00
cba7e426a5 Update README.md 2018-01-31 06:35:47 -08:00
01e7cc9620 Update README.md 2018-01-31 06:34:50 -08:00
5a5497b745 add close ws test 2018-01-30 16:04:04 -08:00
b698e3546b link to websocket example 2018-01-30 15:26:58 -08:00
e99a5e8144 drop local actix ref 2018-01-30 15:19:30 -08:00
577f91206c added support for websocket testing 2018-01-30 15:13:33 -08:00
76f9542df7 rename module 2018-01-30 13:04:52 -08:00
9739168d48 fix limit usage for Request/Response Body future 2018-01-30 12:44:14 -08:00
5cbaf3a1b8 add client ssl support 2018-01-30 11:17:17 -08:00
a02e0dfab6 initial work on client connector 2018-01-29 23:01:20 -08:00
5cc3bba5cc change ws client names 2018-01-29 15:45:37 -08:00
6e51573975 app veyor config 2018-01-29 14:51:34 -08:00
b686f39d0b complete impl for client request and response 2018-01-29 14:44:25 -08:00
6416a796c3 add ClientRequest and ClientRequestBuilder 2018-01-29 11:45:33 -08:00
b6a394a113 added StaticFiles::inex_file config 2018-01-29 03:23:45 -08:00
456fd1364a add handle method to contexts 2018-01-28 09:47:46 -08:00
f3cce6a04c update websocket example 2018-01-28 09:07:12 -08:00
9835a4537a update websocket example 2018-01-28 08:58:18 -08:00
715ec4ae2f update actix 2018-01-28 08:26:36 -08:00
55b2fb7f77 update example 2018-01-28 01:04:58 -08:00
7c7743c145 use right path 2018-01-27 22:52:17 -08:00
826fc62299 disable websocket-chat example 2018-01-27 22:44:50 -08:00
5dd2e7523d basic websocket client 2018-01-27 22:03:03 -08:00
4821d51167 fix actix compatibility 2018-01-27 11:15:03 -08:00
c446be48e3 min rust version 1.21 2018-01-27 10:58:09 -08:00
042f8391bb Merge branch 'master' of github.com:actix/actix-web 2018-01-27 10:05:07 -08:00
d4bc3294a3 actix compatibility 2018-01-27 10:04:56 -08:00
04d53d6f57 Merge pull request #59 from andreevlex/fix-cors
spelling check cors example
2018-01-26 21:42:36 -08:00
881e0e0346 spelling check 2018-01-27 08:38:17 +03:00
b9f8a00ba3 update cors example readme 2018-01-26 19:56:34 -08:00
99bed67bec rename cors example 2018-01-26 19:52:20 -08:00
52a454800f cleanup cors example 2018-01-26 19:51:13 -08:00
c09c8e4980 Merge pull request #58 from krircc/master
add actix-web-cors example
2018-01-26 19:43:40 -08:00
b931dda1fe Merge branch 'master' into master 2018-01-26 19:42:06 -08:00
74166b4834 add actix-web-cors example 2018-01-27 11:00:26 +08:00
4abb769ee5 fix request json loader; mime_type() method 2018-01-25 21:50:28 -08:00
e8e2ca1526 refactor alpn support; upgrade openssl to 0.10 2018-01-25 10:24:04 -08:00
78967dea13 stop http context immediately 2018-01-24 20:17:14 -08:00
58a5d493b7 re-eanble write backpressure for h1 connections 2018-01-24 20:12:49 -08:00
c5341017cd fix typo 2018-01-23 15:39:53 -08:00
f4873fcdee stop websocket context 2018-01-23 15:35:39 -08:00
35efd017bb impl waiting for HttpContext 2018-01-23 09:42:04 -08:00
fb76c490c6 mention tokio handle in guide 2018-01-22 20:10:05 -08:00
3653c78e92 check example on stable 2018-01-22 19:49:19 -08:00
1053c44326 pin new actix version 2018-01-22 17:01:54 -08:00
e6ea177181 impl WebsocketContext::waiting() method 2018-01-22 16:55:50 -08:00
1957469061 code of conduct 2018-01-21 15:29:02 -08:00
2227120ae0 exclude examples 2018-01-21 09:09:19 -08:00
21c8c0371d travis config 2018-01-21 08:50:29 -08:00
1914a6a0d8 Always enable content encoding if encoding explicitly selected 2018-01-21 08:31:46 -08:00
1cff4619e7 reduce threshold for content encoding 2018-01-21 08:12:32 -08:00
7bb7adf89c relax InternalError constraints 2018-01-20 22:02:42 -08:00
f55ff24925 fix guide example 2018-01-20 21:40:18 -08:00
f5f78d79e6 update doc strings 2018-01-20 21:16:31 -08:00
9180625dfd refactor helper error types 2018-01-20 21:11:46 -08:00
552320bae2 add error logging guide section 2018-01-20 20:21:01 -08:00
7cf221f767 Log request processing errors 2018-01-20 20:12:24 -08:00
98931a8623 test case for broken transfer encoding 2018-01-20 16:51:18 -08:00
ae10a89014 use ws masking from tungstenite project 2018-01-20 16:47:34 -08:00
71d534dadb CORS middleware: allowed_headers is defaulting to None #50 2018-01-20 16:36:57 -08:00
867bb1d409 Merge branch 'master' of github.com:actix/actix-web 2018-01-20 16:12:51 -08:00
91c44a1cf1 Fix HEAD requests handling 2018-01-20 16:12:38 -08:00
3bc60a8d5d Merge pull request #53 from andreevlex/spelling-check-2
spelling check
2018-01-16 12:07:58 -08:00
58df8fa4b9 spelling check 2018-01-16 21:59:33 +03:00
81f92b43e5 Merge pull request #52 from andreevlex/spelling-check
spelling check
2018-01-15 14:16:54 -08:00
e1d9c3803b spelling check 2018-01-16 00:47:25 +03:00
a7c24aace1 flush is useless 2018-01-14 19:28:34 -08:00
89a89e7b18 refactor shared bytes api 2018-01-14 17:00:28 -08:00
3425f7be40 fix tests 2018-01-14 14:58:58 -08:00
09a6f8a34f disable alpn feature 2018-01-14 14:44:32 -08:00
7060f298b4 use more binary 2018-01-14 14:40:39 -08:00
33dbe15760 use Binary for writer trait 2018-01-14 13:50:38 -08:00
e95c7dfc29 use local actix-web for examples 2018-01-13 19:04:07 -08:00
927a92fcac impl HttpHandler for Box<HttpHandler> and add helper method Application::boxed() #49 2018-01-13 18:58:17 -08:00
2b0f3d2a9a prepare release 2018-01-13 16:57:01 -08:00
93fdb596d4 Allow to explicitly disable chunked encoding 2018-01-13 16:17:33 -08:00
305666067e Do not enable chunked encoding for HTTP/1.0 2018-01-13 12:46:43 -08:00
b805d87ee7 no need for custom cookie module 2018-01-13 11:33:42 -08:00
bc6bb9984f user guide spelling 2018-01-13 11:17:48 -08:00
c043fd7912 Merge pull request #47 from belltoy/master
fix directory entry path
2018-01-13 11:16:53 -08:00
781282897a fix directory entry path 2018-01-13 08:37:27 +00:00
a9c71b2894 add link to cors middleware 2018-01-12 13:10:12 -08:00
edd26837dd update dependency specs in user guide 2018-01-12 12:54:57 -08:00
3105bca13b use cookie-rs released create 2018-01-12 12:32:54 -08:00
c470e7a02b use flate2 released crate 2018-01-12 12:31:33 -08:00
8a96e8fdd0 disable compression for static files 2018-01-11 23:49:53 -08:00
e919ec485e cleanup http channel 2018-01-11 22:06:06 -08:00
e482b88741 refactor http protocol selection procedure 2018-01-11 21:48:36 -08:00
eb8052b936 fix cors tests 2018-01-11 20:20:50 -08:00
dab918261c fix cors allowed header validation 2018-01-11 20:11:34 -08:00
11342e4566 add link to gitter 2018-01-11 18:49:30 -08:00
f7b895b53a add link to github 2018-01-11 18:47:34 -08:00
ac89880c0a move encoding to server 2018-01-11 18:41:33 -08:00
8a058efb4e move server protocol impl to submodule 2018-01-11 18:35:05 -08:00
fa93701bee upgrade packages 2018-01-11 16:47:55 -08:00
0707dfe5bb flush stream on drain 2018-01-11 16:22:27 -08:00
0a41ecd01d disable test 2018-01-11 15:38:57 -08:00
0648ad6f33 fix implicit chunked encoding 2018-01-11 15:26:46 -08:00
728d4f1f57 clean cargo before running skeptic tests 2018-01-11 11:39:17 -08:00
d152860fa7 add Cors::register method 2018-01-11 11:14:18 -08:00
43f14224b1 properly enable encoding tests 2018-01-10 22:42:26 -08:00
f7d9b45e64 travis config 2018-01-10 21:49:23 -08:00
448b73a4b5 encoding tests 2018-01-10 21:47:30 -08:00
1a31554ee6 travis config 2018-01-10 21:02:28 -08:00
49cdddf479 upgrade flate package 2018-01-10 20:28:06 -08:00
aed90ed458 rename payload 2018-01-10 20:08:13 -08:00
e0faf3f69c refactor pipeline impl 2018-01-10 16:45:57 -08:00
f7807e43d8 cleanup Binary type; more cors tests 2018-01-10 15:28:33 -08:00
fee54d1de0 tests for cors response 2018-01-10 14:56:45 -08:00
1445cc7a2c test for cors 2018-01-10 14:21:48 -08:00
16e9512457 better names for cors errors 2018-01-10 14:20:00 -08:00
615db0d9d8 complete cors implementation 2018-01-10 13:41:33 -08:00
3f3dcf413b move websocket code to submodule 2018-01-10 11:13:29 -08:00
d85081b64e update websocket examples 2018-01-10 10:40:14 -08:00
4b72a1b325 create custom WebsocketContext for websocket connection 2018-01-10 10:12:34 -08:00
8aae2daafa update example 2018-01-10 07:55:25 -08:00
d7f59ce481 add cors preflight request support 2018-01-09 23:55:42 -08:00
ce78f17a79 refactor Middleware trait, use Result 2018-01-09 22:48:35 -08:00
16310a5ebd initial work on cors middleware 2018-01-09 22:33:51 -08:00
e8412672a2 add resource level middlewares support 2018-01-09 20:00:18 -08:00
6c7dda495b add very simple http/2 test 2018-01-09 12:49:46 -08:00
584d0c9e99 Merge branch 'master' of github.com:actix/actix-web 2018-01-09 10:08:14 -08:00
a159a9cd6e cleanup doc tests 2018-01-09 10:08:06 -08:00
9d4e926302 Merge pull request #45 from ami44/master
fix url
2018-01-08 11:33:36 -08:00
41c94a1220 fix url 2018-01-08 19:10:47 +01:00
c7798ef45d update examples 2018-01-07 19:40:42 -08:00
d696c1692e Merge branch 'master' of github.com:actix/actix-web 2018-01-07 19:10:55 -08:00
f90bc0caae do no stop on write_eof 2018-01-07 19:10:42 -08:00
f802fe09e6 fix context poll 2018-01-07 17:13:49 -08:00
513fcd4a47 Update README.md 2018-01-07 08:33:06 -08:00
c28d052d22 Merge pull request #44 from krircc/master
IT's not true, actix-web are more features than other rust web frameworks
2018-01-07 08:32:08 -08:00
550f68ca05 Merge branch 'master' into master 2018-01-07 08:31:57 -08:00
3074071d03 Merge branch 'master' into master 2018-01-07 08:31:31 -08:00
3ffefb8b29 Merge pull request #42 from ami44/master
upd examples basics
2018-01-07 08:30:42 -08:00
3cf2fbbb23 Merge branch 'master' into master 2018-01-07 12:00:24 +01:00
896981cdf8 update examples 2018-01-06 23:22:10 -08:00
71da72efdb use general context impl 2018-01-06 22:59:39 -08:00
5e9b94a6dd Update README.md 2018-01-07 11:07:51 +08:00
665f4edf6b upd examples basics 2018-01-06 16:43:59 +01:00
247c23c1ea no need for StreamHandler 2018-01-06 01:06:35 -08:00
3ed9e872ad subscriber to os signals automatically 2018-01-05 16:32:36 -08:00
473ec38439 use dev cookies package as temp solution for ring problem 2018-01-05 14:50:33 -08:00
524493e0b0 pin nightly 2018-01-05 14:29:40 -08:00
5ae646332e update example to use actix 0.4 2018-01-05 14:01:19 -08:00
5ff35f5b99 upgrade to actix 0.4 2018-01-05 13:30:21 -08:00
dea354d6d8 fix basic example in guide 2018-01-04 16:21:18 -08:00
20d5c61c11 set nodelay for streams 2018-01-04 09:32:47 -08:00
91230afc44 fix time calculations 2018-01-04 09:32:33 -08:00
afeffe4b19 encode returns result 2018-01-04 09:32:15 -08:00
fdf7726831 update changelog 2018-01-03 23:59:12 -08:00
9559f6a175 introduce IoStream trait for low level stream operations 2018-01-03 23:41:55 -08:00
1f7aee23df shutdown io streams before exit 2018-01-03 22:43:44 -08:00
bf11bfed8e use explicit actix:: mod 2018-01-03 19:11:40 -08:00
e439d0546b * fix force_close
* shutdown io before exit

* fix response creation with body from pool
2018-01-03 18:21:34 -08:00
8348c830e2 no need for mut ref 2018-01-03 10:57:57 -08:00
ae084d1146 added helper future for reading request body 2018-01-03 09:23:58 -08:00
88031b7fde remove debug prints 2018-01-03 09:00:22 -08:00
70ea43b3c0 fix drain support for actor; make pattern more reusable 2018-01-02 23:43:17 -08:00
9e6d090fd0 update readme example 2018-01-02 19:57:25 -08:00
7af3b3f956 update example 2018-01-02 19:43:59 -08:00
3a59344ffb update h2 lib 2018-01-02 19:37:33 -08:00
3768a2885d fix examples 2018-01-02 15:52:11 -08:00
f0fdcc9936 handle application prefix for handlers; use handler for StaticFiles 2018-01-02 15:23:31 -08:00
77ba1de305 flush encoder 2018-01-02 14:53:51 -08:00
fb2c78d9fc add hello-world example 2018-01-02 13:42:30 -08:00
b49eadf7e5 fix content length serialization #33 2018-01-02 13:39:32 -08:00
9040f588af allow to handle entire sub path 2018-01-02 13:09:02 -08:00
284b59722a update websocket example 2018-01-01 09:31:42 -08:00
e798af26a2 Merge pull request #27 from ami44/master
move examples/websocket.rs to examples/websocket
2018-01-01 12:26:07 +01:00
fc88bb294a Merge remote-tracking branch 'upstream/master' 2018-01-01 12:22:03 +01:00
f3a90a2829 add example to workspace 2017-12-31 22:22:56 -08:00
d2f54b7d19 use workspace 2017-12-31 21:55:25 -08:00
8e89ff1d1e fix examples 2017-12-31 20:08:35 -08:00
cc38b30f7b refactor http actor usage 2017-12-31 17:26:32 -08:00
967d3244d7 fix http/2 support 2017-12-31 13:22:11 -08:00
d8548ad83b update examples/diesel readme 2017-12-31 08:12:26 +01:00
5741b8b372 add examples/websocket 2017-12-30 22:43:10 +01:00
7962d28a6d move examples/websocket.rs to examples/websocket 2017-12-30 21:47:39 +01:00
e18f9f3f3a Merge pull request #1 from actix/master
Update from original
2017-12-30 21:27:48 +01:00
73e2773a10 minor fix guide/ 2017-12-30 21:13:23 +01:00
c998c75515 move examples/state.rs to examples/state 2017-12-30 21:08:54 +01:00
f1f5b23e77 fix readme examples/signal 2017-12-30 21:08:12 +01:00
76b03851e6 fix examples - disable signal if windows 2017-12-30 21:05:03 +01:00
87188e1505 minor fix examples/websocket-chat 2017-12-30 16:50:49 +01:00
df393df547 move example/basic.rs to examples/basic 2017-12-30 16:50:17 +01:00
a1dc5a6bd1 update examples/tls/README 2017-12-30 16:24:50 +01:00
8e580ef7b9 add README examples/template_tera 2017-12-30 16:10:29 +01:00
12345004dd add README examples/signals 2017-12-30 16:10:00 +01:00
a1a77600c6 add README example/multipart 2017-12-30 16:09:39 +01:00
d7d9e8c0e9 update json example 2017-12-30 16:08:18 +01:00
e93af57fa7 add json example link 2017-12-30 16:07:39 +01:00
a166fc82f4 add json-rust example 2017-12-30 15:24:12 +01:00
2d769f805a add diesel+postgresql link 2017-12-30 12:21:34 +01:00
6ea894547d better application handling, fix url_for method for routes with prefix 2017-12-29 14:04:13 -08:00
491d43aa8c update tests 2017-12-29 11:49:36 -08:00
1baead993a call poll_io recursevely aftre drain completion 2017-12-29 11:45:56 -08:00
3d3e4dae9a refactor IntoHttpHandler trait 2017-12-29 11:33:04 -08:00
1d195a2cf2 make Pipeline private 2017-12-29 09:16:50 -08:00
d87fafb563 fix and refactor middleware runner 2017-12-29 01:01:31 -08:00
308df19865 update readme 2017-12-28 16:27:08 -08:00
538fea8027 add graceful shutdown system 2017-12-28 16:25:47 -08:00
3f4898a6d1 add StopWorker message 2017-12-28 13:07:29 -08:00
6a2bb9a473 split worker code to separate module 2017-12-28 12:38:37 -08:00
d8b0ce88a5 fix guide example 2017-12-28 12:27:46 -08:00
783e19c1bf fix RequestSession impl for HttpRequest 2017-12-28 11:43:45 -08:00
d80a0c9f94 add support for unix signals 2017-12-28 11:36:20 -08:00
02b37570f4 flaky test 2017-12-28 09:11:25 -08:00
820404cdd2 Merge pull request #20 from ami44/master
set session name
2017-12-28 04:23:41 -08:00
27b0dfd761 set sessio name 2017-12-28 13:02:46 +01:00
b714e1f4ce fix example 2017-12-27 19:29:04 -08:00
093d0bae40 Param ctor is private 2017-12-27 19:19:28 -08:00
8941557da6 add parameter container iterator 2017-12-27 19:09:36 -08:00
6bb893deab use Params object for query 2017-12-27 19:02:29 -08:00
19e1c1b75b use Cow for Params type 2017-12-27 18:41:09 -08:00
556de72932 add server spawn method 2017-12-27 17:49:10 -08:00
4d741b4de5 Fix typos 2017-12-27 13:26:31 -08:00
0589f2ee49 add server management commands 2017-12-27 12:58:32 -08:00
da8aa8b988 use mio for accept loop 2017-12-27 11:22:27 -08:00
be1cd2936d check example in 1.20 2017-12-27 09:49:59 -08:00
e1fb32c6e5 Update .travis.yml 2017-12-27 07:36:24 -08:00
5df5cc7374 fix guide example 2017-12-26 21:33:23 -08:00
0d21c2da22 various typos 2017-12-26 21:07:51 -08:00
183bcd38f8 modify unused_addr method; update websockt guide section 2017-12-26 20:52:21 -08:00
3abd0db6b1 restore server start test 2017-12-26 20:07:31 -08:00
29adc20581 rename module 2017-12-26 19:59:41 -08:00
743235b8fd add unit test helper 2017-12-26 19:48:02 -08:00
7f77ba557d add testing section to guide 2017-12-26 17:14:37 -08:00
d3b7d2d6b3 allow to use application factory for test server 2017-12-26 16:47:55 -08:00
f6510161b5 add simple TestServer for integrational tests cases 2017-12-26 16:35:00 -08:00
e3b0f02794 fix type for disable feartures 2017-12-26 15:17:20 -08:00
9521de5746 HttpServer::addrs() return all bound socket addresses 2017-12-26 14:45:38 -08:00
dd3a2aa68a add HttpServer::server_hostname method 2017-12-26 14:36:03 -08:00
cce9c68a10 add doc string 2017-12-26 12:46:27 -08:00
5e17a846af add notes on sync primitives 2017-12-26 11:19:08 -08:00
030a70841a add link to gitter 2017-12-26 11:04:25 -08:00
e4bfef9d26 fix tests 2017-12-26 09:28:24 -08:00
cf8c2ca95e refactor Handler trait, use mut self 2017-12-26 09:00:45 -08:00
b61a07a320 more info for middleware guide 2017-12-26 07:58:21 -08:00
ffb5742b71 fix tests 2017-12-25 19:42:55 -08:00
465a87a7cf right version 2017-12-25 13:44:50 -08:00
5b65987f6a write response optimizations 2017-12-25 13:40:06 -08:00
89c9dfb5bc update getting started guide section 2017-12-25 08:19:33 -08:00
a578262f73 update json example and guide info 2017-12-25 08:12:13 -08:00
b0c8fa03f0 use specific nightly version for appveyor 2017-12-25 07:33:05 -08:00
98b0e023f3 optimize payload detection 2017-12-25 07:31:12 -08:00
012d55e424 Set nightly version 2017-12-25 05:49:56 -08:00
f1e82ebc1e better connect handling 2017-12-24 16:15:40 -08:00
ddd9c24bb2 optimize payload type detection 2017-12-24 14:29:19 -08:00
9f9c75d832 simplify drain feature 2017-12-24 11:58:09 -08:00
eaab28cd3b proper fix for compression 2017-12-21 12:57:59 -08:00
c35d294611 fix compression 2017-12-21 12:54:18 -08:00
18f3841783 update test 2017-12-20 23:36:52 -08:00
0567e6fb0a fix typos in guide 2017-12-20 23:27:30 -08:00
55534bff8c simplify guide examples 2017-12-20 23:21:26 -08:00
bca1dd4f9e update doc strings 2017-12-20 23:19:21 -08:00
0a68811dce cleanup more examples 2017-12-20 21:06:04 -08:00
406d2c41e9 add doc string 2017-12-20 20:56:17 -08:00
63ddc07ccb added JsonBody future 2017-12-20 20:30:54 -08:00
33b2be3281 move json responder to separate module 2017-12-20 17:51:28 -08:00
bf23aa5d4b move db code to separate module 2017-12-20 17:44:19 -08:00
3c5fd18e02 cleanup examples 2017-12-20 16:32:31 -08:00
4dd3382ac7 update example 2017-12-20 16:13:21 -08:00
50891986bc simplify json example 2017-12-20 16:05:07 -08:00
df2aa42dad cleanup example 2017-12-20 15:45:26 -08:00
c36ad06332 more general Responder implementaiton for response future 2017-12-20 15:26:28 -08:00
821c96c37c check json example during travis build 2017-12-20 15:20:28 -08:00
cbb81bc747 json request example 2017-12-20 15:12:43 -08:00
79f047f5be remove box from predicates 2017-12-20 13:23:50 -08:00
813b56ebe5 make async handler future more generic 2017-12-20 12:51:39 -08:00
c3a39e026d Merge branch 'master' of github.com:actix/actix-web 2017-12-20 11:37:36 -08:00
e05596b65d upgrade actix min version 2017-12-20 11:37:27 -08:00
65767558fb Update README.md 2017-12-20 08:00:28 -08:00
7fc7d6e17a update guide 2017-12-19 22:36:06 -08:00
c47e2ccfee update guide examples 2017-12-19 18:44:17 -08:00
d0c01c2cdd update guide example 2017-12-19 18:38:02 -08:00
50b2f62c80 update guide section about ssl 2017-12-19 18:36:29 -08:00
0a96b8c579 update readme 2017-12-19 16:17:27 -08:00
d41aade0b7 update readme 2017-12-19 16:14:47 -08:00
626999bcc9 update doc strings 2017-12-19 16:09:19 -08:00
64d867d9a1 update session guide section 2017-12-19 15:44:25 -08:00
1596f4db73 refactor url encoded body parsing 2017-12-19 14:03:01 -08:00
fa2a3bc55e make method private 2017-12-19 13:11:19 -08:00
52c9865716 split examples check 2017-12-19 12:22:11 -08:00
db7bd962cb fix some doc strings 2017-12-19 11:46:11 -08:00
f858fa7a32 Merge branch 'travis-test' 2017-12-19 11:35:16 -08:00
2bad99b645 better query() method impl; update doc strings 2017-12-19 11:34:51 -08:00
566066e855 check examples 2017-12-19 10:56:48 -08:00
009874125e add client.py comments 2017-12-19 10:25:23 -08:00
2e790dfcc6 add multipart guide section 2017-12-19 10:10:03 -08:00
e3f9345420 multipart field is stream of bytes 2017-12-19 09:55:49 -08:00
790793f8a1 refactor multipart stream creation 2017-12-19 09:51:28 -08:00
13cbfc877d simplify server start method 2017-12-19 09:08:36 -08:00
4f6145e5c7 fix typos 2017-12-19 00:29:25 -08:00
f3b853f224 refactor payload 2017-12-19 00:18:57 -08:00
0cab873066 make payload sender public 2017-12-18 21:58:38 -08:00
64dc6c5771 fix typos 2017-12-18 20:03:42 -08:00
669975df75 fix typos 2017-12-18 20:00:57 -08:00
56fd088163 added database integration guide section 2017-12-18 19:38:16 -08:00
2124730e0a guide update 2017-12-18 18:56:58 -08:00
e9a3845e26 update license in readme 2017-12-18 16:48:30 -08:00
3f0e7456c0 update examples links 2017-12-18 16:42:58 -08:00
1e1da5832f better name 2017-12-18 16:40:33 -08:00
625c4ad0db add more comments 2017-12-18 16:30:35 -08:00
fde94bfe95 added diesel example 2017-12-18 16:25:26 -08:00
3e8a6c3988 add tera example 2017-12-18 13:41:52 -08:00
26af6040ff update tests 2017-12-18 13:26:43 -08:00
9ed4159c0c update examples 2017-12-18 13:06:41 -08:00
27d92f3a23 refactor server bind and start process 2017-12-17 12:35:04 -08:00
4b421b44a2 add mit license 2017-12-17 10:08:44 -08:00
1a51f75ecc update readme 2017-12-17 10:03:37 -08:00
9821c6ea90 update readme 2017-12-16 11:39:56 -08:00
167717d20e update readme 2017-12-16 11:22:39 -08:00
91ffab8f6e update readme 2017-12-16 07:30:53 -08:00
b1f33e29ec simplify content-length calculation 2017-12-16 07:29:15 -08:00
ed8bd3d6a3 h1 cleanups 2017-12-15 22:49:48 -08:00
1daf50095a cleanup response 2017-12-15 20:00:12 -08:00
a8b2f1b821 update tests 2017-12-15 18:49:11 -08:00
1ddcce7b76 hide httpresponse box 2017-12-15 16:24:15 -08:00
c3d5e4301a cleanup h1 parse 2017-12-15 13:10:12 -08:00
71c37bde5a Update README.md 2017-12-15 05:44:10 -08:00
4913e7d3c2 cleanup 2017-12-14 22:22:27 -08:00
d77156c16c fix readme 2017-12-14 20:49:09 -08:00
106f43e874 better SharedBytes usage for h2 2017-12-14 20:48:31 -08:00
2b0994e448 update tests 2017-12-14 20:29:49 -08:00
a2dff8a0b9 update readme 2017-12-14 20:12:28 -08:00
c37565cc4a various server optimizations 2017-12-14 19:34:31 -08:00
b61c2a0cf0 handle keep-alive setting more efficient 2017-12-14 11:20:45 -08:00
c98d320f8c rename FromRequest trait to Responder 2017-12-14 09:43:42 -08:00
355f54efe2 update api docs 2017-12-13 23:35:21 -08:00
8c1487f7f2 update tests 2017-12-13 23:09:35 -08:00
4529efa948 rename module 2017-12-13 22:54:52 -08:00
9d0a64ac98 remove unused file 2017-12-13 22:43:16 -08:00
b7cde3f4a9 update guide 2017-12-13 22:36:28 -08:00
408ddf0be1 add ssl guide ref 2017-12-13 21:56:30 -08:00
406ef20262 add readme 2017-12-13 21:44:16 -08:00
c2751efa87 refactor keep-alive; update guide 2017-12-13 21:38:47 -08:00
653b431895 fix example 2017-12-13 17:28:16 -08:00
96f598f2c4 various optimizations 2017-12-13 16:44:35 -08:00
81f8da03ae refactor http workers 2017-12-13 12:47:07 -08:00
6b61041aec move tests 2017-12-13 11:16:26 -08:00
d4187f682b various cleanups 2017-12-13 11:10:03 -08:00
55204c829c update tests 2017-12-13 08:00:25 -08:00
2e83c5924d cleanup and optimize some code 2017-12-12 21:32:58 -08:00
ab6efd2421 handle http connections in different threads 2017-12-12 17:21:00 -08:00
55818028cb state does not need to be Send 2017-12-12 08:51:16 -08:00
e9aa67b75d http server accepts factory of HttpHandlers 2017-12-12 07:40:36 -08:00
b9da09ddf0 update readme 2017-12-11 19:17:37 -08:00
d7efbb516d fix guide tests 2017-12-11 19:16:45 -08:00
6e3f598c50 fix guide page 2017-12-11 16:50:51 -08:00
007b7ce62f unify route not found handling 2017-12-11 16:26:51 -08:00
b1ae7f95cc update readme example 2017-12-11 15:57:37 -08:00
96381f5d6a fix doc 2017-12-11 14:27:09 -08:00
0f75d066f2 simplify Application creation; update url dispatch guide section 2017-12-11 14:16:29 -08:00
caca907c23 update guide 2017-12-09 14:06:22 -08:00
c5490a851c add guid for path normalization 2017-12-09 13:58:24 -08:00
0388a464ba tests for NormalizePath 2017-12-09 13:25:06 -08:00
71bbe2a5dd update doc string for NormalizePath 2017-12-09 11:55:55 -08:00
7addd2800d add NormalizePath handler 2017-12-09 11:39:13 -08:00
273de2260d refactor pipeline 2017-12-09 05:54:04 -08:00
b98ab2eebe use trait instead of pipeline 2017-12-09 04:33:40 -08:00
4a40b026a4 more error wrappers 2017-12-08 15:52:46 -08:00
a44f71d8c2 make ErrorBadRequest type useful 2017-12-08 15:25:37 -08:00
9043e7286d tests for default predicates 2017-12-08 12:51:44 -08:00
3e91b06241 fix static files 2017-12-08 12:29:28 -08:00
774bfc0a86 use server settings for scheme and host values 2017-12-08 09:48:53 -08:00
1293619096 set server settings to HttpHandler 2017-12-08 09:24:05 -08:00
2192d14eff added ServerSettings 2017-12-07 22:54:44 -08:00
b71ddf7b4c pass local addr to channel; use bitflags 2017-12-07 21:52:46 -08:00
3f06439d3e update examples 2017-12-07 18:08:16 -08:00
d595dd850e load cookies automatically 2017-12-07 18:00:20 -08:00
0abb3863dc simplify api 2017-12-07 17:38:18 -08:00
dff7618f35 rearrange exports 2017-12-07 16:40:29 -08:00
968f5d39d6 added external resources; refactor route recognizer 2017-12-07 16:22:26 -08:00
9e3aa59155 ignore tests 2017-12-07 10:23:14 -08:00
2a0d5db41a more tests 2017-12-06 18:39:13 -08:00
4b03d03404 rearrange exports 2017-12-06 17:06:40 -08:00
9ea0781aba fix test 2017-12-06 16:58:49 -08:00
63502fa833 test for Router::has_route 2017-12-06 16:40:23 -08:00
a18bd5dac0 add doc ref 2017-12-06 16:34:54 -08:00
0dd27bd224 added HttpRequest::url_for 2017-12-06 16:26:27 -08:00
8d52e2bbd9 tests for default resource 2017-12-06 13:02:53 -08:00
c63f058647 simplify application creation 2017-12-06 11:00:39 -08:00
87c7441f7d remove Applicaiton::route, resource is enough 2017-12-06 08:03:08 -08:00
04ded5ba68 hide pkcs 2017-12-06 07:49:01 -08:00
903b391e0a move ConnectionInfo to dev 2017-12-06 07:47:42 -08:00
c2bfc091bd fix travis 2017-12-05 22:14:38 -08:00
20af8822fd cleanup 2017-12-05 21:53:00 -08:00
d7e65b6212 add ConnectionInfo tests 2017-12-05 21:41:30 -08:00
c3de32c3b3 added ConnectionInfo 2017-12-05 17:09:15 -08:00
d8b880e167 work on resource_path api 2017-12-05 13:31:06 -08:00
3de43c2a46 update readme 2017-12-05 12:25:57 -08:00
bd1e9abdd8 simple readme example 2017-12-05 11:50:09 -08:00
86d7290f9e update tests 2017-12-05 11:43:41 -08:00
a83d9b24ae extrat elements of path pattern 2017-12-05 11:31:35 -08:00
3c9b6ea619 update guide 2017-12-04 20:38:38 -08:00
fd6b243cd6 update examples 2017-12-04 16:32:31 -08:00
2950c90c77 doc fixes 2017-12-04 16:26:40 -08:00
f4e9fc7b6a rename async to a 2017-12-04 16:09:22 -08:00
e98972e93b exclude example from code coverage 2017-12-04 15:35:07 -08:00
e332c1242f use Route for Applicaiton handlers 2017-12-04 14:53:40 -08:00
f5d6179a34 renamed Route::handler to Route::f, added Route::h to register Handler 2017-12-04 14:07:53 -08:00
03f7d95d88 fix fmratting 2017-12-04 13:36:28 -08:00
a163e75318 drop tail path pattern 2017-12-04 13:34:55 -08:00
3bf3738e65 introduce route predicates 2017-12-04 13:32:05 -08:00
57fd35ffc1 added default headers middleware 2017-12-03 20:47:15 -08:00
d35be02587 cleanup 2017-12-03 20:09:46 -08:00
57c53bd2a0 add encoding section 2017-12-03 18:58:15 -08:00
319e9bbd05 added Json response support 2017-12-03 18:51:52 -08:00
5decff9154 added fs tests 2017-12-03 18:15:09 -08:00
69f0c098e3 check show_index 2017-12-03 16:58:31 -08:00
5abc46034a refactor static files 2017-12-03 16:57:25 -08:00
7c6faaa8e0 add Item and Error to FromRequest trait 2017-12-03 14:22:04 -08:00
6bc7d60f52 more default impls for FromRequest 2017-12-02 17:14:55 -08:00
fb3185de94 rename module 2017-12-02 16:47:02 -08:00
61744b68a1 introduce custom FromRequest traint for conversion into Reply 2017-12-02 16:37:21 -08:00
187948ddd1 error response for io::Error 2017-12-02 14:58:22 -08:00
29a26b3236 code cleanup 2017-12-02 12:14:16 -08:00
d0b9d9c1d6 content-encoding; try cargo tarpaulin 2017-12-02 11:41:20 -08:00
0fc01c48d1 return bad request for param parse error 2017-12-02 11:03:41 -08:00
ebfd3ac275 tests for PathBuf::from_param 2017-12-02 10:43:14 -08:00
d8f27e95a6 added FromParam trait for path segment conversions, FramParam impl for PathBuf 2017-12-02 10:18:54 -08:00
d03d1207a8 add http2 section 2017-12-02 00:36:50 -08:00
8f33dec026 add logging doc section 2017-12-02 00:24:26 -08:00
0dae109172 missing files 2017-12-01 23:42:21 -08:00
1a5df7192e add multiple apps example 2017-12-01 23:32:15 -08:00
3ffd36eee2 some more guide 2017-12-01 23:06:15 -08:00
c3a0a4457a add appl builder async method; add async handler section 2017-12-01 21:58:19 -08:00
e6feec62a8 simplier examples 2017-12-01 21:31:38 -08:00
f0c346f18c handler info 2017-12-01 21:29:22 -08:00
186726fbad tests for Completed state 2017-12-01 19:57:34 -08:00
97bed17fd2 test for completed pipeline state 2017-12-01 16:10:01 -08:00
47645626c4 refactor pipeline 2017-12-01 15:45:15 -08:00
9a1ba527c0 recognizer tests 2017-11-30 19:34:33 -08:00
3fcd5f6935 use http::Uri for uri parsing 2017-11-30 19:01:25 -08:00
7135c0163b simlify code 2017-11-30 18:27:27 -08:00
f53f35f364 added tail pattern 2017-11-30 15:48:09 -08:00
07cc017320 make Task private 2017-11-30 15:13:56 -08:00
271a292ea5 no need to store disconnected state on task 2017-11-30 14:44:58 -08:00
6e138bf373 refactor streaming responses 2017-11-30 14:42:20 -08:00
a0bca2d4cf fix typo 2017-11-30 07:42:02 -08:00
6c4fdf604b do not set content encoding header for upgraded connection 2017-11-29 19:40:27 -08:00
e4f8551cba do not com press upgrade connection 2017-11-29 19:36:55 -08:00
559b1c50a3 do not encode payload less that 1024 bytes 2017-11-29 19:18:37 -08:00
d2eae3d5b3 simplify Handler trait 2017-11-29 15:10:45 -08:00
27035c9454 fixes 2017-11-29 14:22:47 -08:00
991dd107b1 update ws doc 2017-11-29 14:12:27 -08:00
ffb2e3c0ab update examples 2017-11-29 14:03:18 -08:00
acc2fff655 export and simplify HttpHandler trait 2017-11-29 13:53:52 -08:00
427566b90d export Handler 2017-11-29 13:41:51 -08:00
16ceb741b8 refactor RouteHandler trait 2017-11-29 13:26:55 -08:00
6f833798c7 refactor http actor handling 2017-11-29 10:31:24 -08:00
6177d86d97 refactor handler rtype handling 2017-11-29 09:17:00 -08:00
e9bfab8012 add deref for payload item 2017-11-28 19:51:39 -08:00
afeecea05f refactor reply handling 2017-11-28 19:49:17 -08:00
6f5b58b691 more guide 2017-11-28 18:00:10 -08:00
987b275c3f add response test 2017-11-28 14:29:22 -08:00
932e751240 add status code helper method for http response 2017-11-28 14:23:42 -08:00
706e2a07de add helper converters into response 2017-11-28 13:52:53 -08:00
a3022e6d88 some overview text for guide 2017-11-28 12:44:59 -08:00
b55d69b4c2 better handler result handling 2017-11-28 12:42:53 -08:00
0bd8725426 make resource handler result more generic 2017-11-28 12:28:51 -08:00
ac3fe30d19 use git master for examples 2017-11-28 10:27:58 -08:00
88eb6bc6a2 build mdbook 2017-11-28 09:57:27 -08:00
91cefa8e2f use precompiled mdbook 2017-11-28 09:40:22 -08:00
26413d1d61 add link to guide 2017-11-27 19:56:14 -08:00
06f9b7b52f fix travis config 2017-11-27 16:49:25 -08:00
599f3c26e0 start working on guide 2017-11-27 16:41:37 -08:00
b5a4f6f855 hellper method for json body 2017-11-27 10:39:47 -08:00
42716d3252 update tests 2017-11-26 22:59:04 -08:00
170d3163f3 better export naming 2017-11-26 22:53:28 -08:00
0519056199 consistent naming 2017-11-26 22:31:29 -08:00
45433f71e5 impl Default trait for HttpRequest 2017-11-26 22:20:28 -08:00
b62b303fdb remove unneeded directives 2017-11-26 22:11:51 -08:00
8e80fed2af added urlencoded errors 2017-11-26 22:00:25 -08:00
fdafb0c848 simplify middleware api; fix examples 2017-11-26 21:47:33 -08:00
5a3b6638a7 move state to request object 2017-11-26 21:18:38 -08:00
8e0a7f44d4 pass request by value 2017-11-26 20:34:20 -08:00
eb7f48a1c6 include payload into request 2017-11-26 19:00:57 -08:00
32483735ba cookie session implementation 2017-11-26 17:34:11 -08:00
53ce186294 cleanup pipeline 2017-11-25 12:05:27 -08:00
37c1e78c7a added helper Task::error method 2017-11-25 10:52:43 -08:00
45ecb87eab allow middlware error result 2017-11-25 10:24:45 -08:00
54bbc98343 cookie session prototype 2017-11-25 09:52:32 -08:00
f4972150cc better middleware error handling 2017-11-25 09:40:57 -08:00
1fc64bc83d better pipeline error handling 2017-11-25 09:28:25 -08:00
64ade803f9 store error for error response 2017-11-25 09:03:44 -08:00
940bc08aba remove unused imports 2017-11-24 22:19:06 -08:00
7569036dd4 refactor request pipeline 2017-11-24 22:15:52 -08:00
59b8214685 better nightly detection 2017-11-24 10:28:43 -08:00
f33c489154 added default ErrorResponse for std::error::Error 2017-11-24 10:03:13 -08:00
5529ea0428 better logger format test 2017-11-23 16:53:02 -08:00
39a20fb95d use env_logger for logger tests 2017-11-23 15:48:59 -08:00
155a636487 more logger tests 2017-11-23 15:37:11 -08:00
e571587a8c refactor logger middleware 2017-11-23 15:17:16 -08:00
5945035fc3 better method name 2017-11-19 18:55:37 -10:00
766e243c63 more Body tests 2017-11-19 18:32:37 -10:00
83862dfbb4 update payload tests 2017-11-19 18:26:30 -10:00
c44e4ad100 expect error tests 2017-11-19 18:02:31 -10:00
1a0e87ac3c add tests for errors 2017-11-19 17:58:47 -10:00
72edd75eab add custom ExceptError 2017-11-19 17:51:14 -10:00
78d8d21196 cleanup error 2017-11-19 17:26:31 -10:00
fd3dcdf0f6 use failure from crates 2017-11-18 06:50:56 -10:00
a87784ba15 use Result intead of HandlerResult 2017-11-18 06:50:07 -10:00
c800bf55f5 update tests 2017-11-15 20:28:02 -10:00
0143e18fe9 fix extern crate 2017-11-15 20:09:37 -10:00
de71ad7de4 refactor error handling 2017-11-15 20:06:28 -10:00
c565965865 rename BinaryBody 2017-11-10 13:42:32 -08:00
f2520d2d79 update logger doc 2017-11-10 13:34:16 -08:00
be3a1ab770 use remote addr in logger if available 2017-11-10 13:26:12 -08:00
f369d9af0e make remote addr available to http request 2017-11-10 13:08:15 -08:00
265628750c refactor logger middleware 2017-11-10 12:29:54 -08:00
657efb8cce fix readme 2017-11-09 22:18:59 -08:00
40c1d3b711 refactor middlewares 2017-11-09 22:08:54 -08:00
51cd08ef57 store cookies load state 2017-11-08 21:01:56 -08:00
2a319d733f enable secure cookies 2017-11-08 20:57:59 -08:00
519a9e64f8 cleanup tls example 2017-11-08 20:29:48 -08:00
4d575c6269 update readme 2017-11-08 20:25:14 -08:00
e9fe2ba740 use bytes::Writer 2017-11-08 20:08:16 -08:00
7565ed8e06 use higher pripority for br 2017-11-08 19:42:13 -08:00
02fb424659 add custom Debug impl for HttpResponse 2017-11-08 19:31:25 -08:00
1392b2b171 Update README.md 2017-11-08 16:48:20 -08:00
e558414867 add response content encoding 2017-11-08 16:44:46 -08:00
76b8104f52 use version in readme 2017-11-07 16:09:37 -08:00
2eb3ad0de3 better name 2017-11-07 16:08:10 -08:00
6974213036 use new brotli2 version 2017-11-07 15:59:37 -08:00
72c8ad9fe1 fix appveyor config for gnu target 2017-11-07 09:43:39 -08:00
a65fd695e1 refactor content encoding 2017-11-06 16:23:58 -08:00
994d0afd80 allow to set/change responses content encoding 2017-11-06 14:56:38 -08:00
2379bcbf39 added content-encoding support to h2 2017-11-06 09:35:52 -08:00
bddd8e9c2e better deflate decoding 2017-11-06 09:24:19 -08:00
c2978a6eea add content encoding decompression 2017-11-06 01:27:46 -08:00
b467ddf970 test with alpn feature 2017-11-04 15:16:49 -07:00
3f649b8e07 fix name 2017-11-04 14:07:15 -07:00
e9e247217a update readme 2017-11-04 13:49:51 -07:00
f23974cfb5 update readme 2017-11-04 13:49:05 -07:00
53868a88fa add keep-alive for h2 connection 2017-11-04 13:24:57 -07:00
28652a3ba8 update readme 2017-11-04 12:36:37 -07:00
41be1db8bc fix link 2017-11-04 12:35:55 -07:00
67f3ad31ab update readme 2017-11-04 12:35:19 -07:00
d7d3d663e9 refactor server impl and add support for alpn http2 negotiation 2017-11-04 12:33:14 -07:00
32cefb8455 implement h2 writer 2017-11-04 09:07:44 -07:00
4add742aba refactor task impl, extract stream writer to separate struct 2017-11-03 13:48:00 -07:00
f010672885 rename modules 2017-11-03 13:48:00 -07:00
c14e6c9008 make possible to use async handler 2017-11-03 13:35:34 -07:00
ec3b139273 Allow to start tls server with HttpServer::serve_tls 2017-11-01 16:34:58 -07:00
a12e5e9cf5 bump version 2017-10-30 20:46:39 -07:00
224 changed files with 36150 additions and 6950 deletions

View File

@ -3,6 +3,15 @@ environment:
PROJECT_NAME: actix PROJECT_NAME: actix
matrix: matrix:
# Stable channel # Stable channel
- TARGET: i686-pc-windows-gnu
CHANNEL: 1.21.0
- TARGET: i686-pc-windows-msvc
CHANNEL: 1.21.0
- TARGET: x86_64-pc-windows-gnu
CHANNEL: 1.21.0
- TARGET: x86_64-pc-windows-msvc
CHANNEL: 1.21.0
# Stable channel
- TARGET: i686-pc-windows-gnu - TARGET: i686-pc-windows-gnu
CHANNEL: stable CHANNEL: stable
- TARGET: i686-pc-windows-msvc - TARGET: i686-pc-windows-msvc
@ -22,17 +31,23 @@ environment:
CHANNEL: beta CHANNEL: beta
# Nightly channel # Nightly channel
- TARGET: i686-pc-windows-gnu - TARGET: i686-pc-windows-gnu
CHANNEL: nightly CHANNEL: nightly-2017-12-21
- TARGET: i686-pc-windows-msvc - TARGET: i686-pc-windows-msvc
CHANNEL: nightly CHANNEL: nightly-2017-12-21
- TARGET: x86_64-pc-windows-gnu - TARGET: x86_64-pc-windows-gnu
CHANNEL: nightly CHANNEL: nightly-2017-12-21
- TARGET: x86_64-pc-windows-msvc - TARGET: x86_64-pc-windows-msvc
CHANNEL: nightly CHANNEL: nightly-2017-12-21
# Install Rust and Cargo # Install Rust and Cargo
# (Based on from https://github.com/rust-lang/libc/blob/master/appveyor.yml) # (Based on from https://github.com/rust-lang/libc/blob/master/appveyor.yml)
install: install:
- ps: >-
If ($Env:TARGET -eq 'x86_64-pc-windows-gnu') {
$Env:PATH += ';C:\msys64\mingw64\bin'
} ElseIf ($Env:TARGET -eq 'i686-pc-windows-gnu') {
$Env:PATH += ';C:\MinGW\bin'
}
- curl -sSf -o rustup-init.exe https://win.rustup.rs - curl -sSf -o rustup-init.exe https://win.rustup.rs
- rustup-init.exe --default-host %TARGET% --default-toolchain %CHANNEL% -y - rustup-init.exe --default-host %TARGET% --default-toolchain %CHANNEL% -y
- set PATH=%PATH%;C:\Users\appveyor\.cargo\bin - set PATH=%PATH%;C:\Users\appveyor\.cargo\bin
@ -44,6 +59,4 @@ build: false
# Equivalent to Travis' `script` phase # Equivalent to Travis' `script` phase
test_script: test_script:
- cargo build --no-default-features
- cargo clean
- cargo test --no-default-features - cargo test --no-default-features

5
.gitignore vendored
View File

@ -1,7 +1,7 @@
target/
Cargo.lock Cargo.lock
target/
guide/build/
/gh-pages /gh-pages
__pycache__
*.so *.so
*.out *.out
@ -9,7 +9,6 @@ __pycache__
*.pid *.pid
*.sock *.sock
*~ *~
*.egg-info/
# These are backup files generated by rustfmt # These are backup files generated by rustfmt
**/*.rs.bk **/*.rs.bk

View File

@ -1,28 +1,35 @@
language: rust language: rust
sudo: false
rust:
- 1.20.0
- stable
- beta
- nightly
sudo: required
dist: trusty dist: trusty
cache:
cargo: true
apt: true
matrix:
include:
- rust: 1.21.0
- rust: stable
- rust: beta
- rust: nightly
allow_failures:
- rust: nightly
#rust:
# - 1.21.0
# - stable
# - beta
# - nightly-2018-01-03
env: env:
global: global:
- RUSTFLAGS="-C link-dead-code" # - RUSTFLAGS="-C link-dead-code"
- OPENSSL_VERSION=openssl-1.0.2
addons: before_install:
apt: - sudo add-apt-repository -y ppa:0k53d-karl-f830m/openssl
packages: - sudo apt-get update -qq
- libcurl4-openssl-dev - sudo apt-get install -qq libssl-dev libelf-dev libdw-dev cmake gcc binutils-dev libiberty-dev
- libelf-dev
- libdw-dev
- cmake
- gcc
- binutils-dev
- libiberty-dev
# Add clippy # Add clippy
before_script: before_script:
@ -33,7 +40,34 @@ before_script:
- export PATH=$PATH:~/.cargo/bin - export PATH=$PATH:~/.cargo/bin
script: script:
- cargo test --no-default-features - |
if [[ "$TRAVIS_RUST_VERSION" == "stable" ]]; then
cargo clean
USE_SKEPTIC=1 cargo test --features=alpn
else
cargo clean
cargo test -- --nocapture
# --features=alpn
fi
- |
if [[ "$TRAVIS_RUST_VERSION" == "stable" ]]; then
cd examples/basics && cargo check && cd ../..
cd examples/hello-world && cargo check && cd ../..
cd examples/http-proxy && cargo check && cd ../..
cd examples/multipart && cargo check && cd ../..
cd examples/json && cargo check && cd ../..
cd examples/juniper && cargo check && cd ../..
cd examples/protobuf && cargo check && cd ../..
cd examples/state && cargo check && cd ../..
cd examples/template_tera && cargo check && cd ../..
cd examples/diesel && cargo check && cd ../..
cd examples/r2d2 && cargo check && cd ../..
cd examples/tls && cargo check && cd ../..
cd examples/websocket-chat && cargo check && cd ../..
cd examples/websocket && cargo check && cd ../..
cd examples/unix-socket && cargo check && cd ../..
fi
- | - |
if [[ "$TRAVIS_RUST_VERSION" == "nightly" && $CLIPPY ]]; then if [[ "$TRAVIS_RUST_VERSION" == "nightly" && $CLIPPY ]]; then
cargo clippy cargo clippy
@ -42,28 +76,20 @@ script:
# Upload docs # Upload docs
after_success: after_success:
- | - |
if [[ "$TRAVIS_OS_NAME" == "linux" && "$TRAVIS_PULL_REQUEST" = "false" && "$TRAVIS_BRANCH" == "master" && "$TRAVIS_RUST_VERSION" == "nightly" ]]; then if [[ "$TRAVIS_OS_NAME" == "linux" && "$TRAVIS_PULL_REQUEST" = "false" && "$TRAVIS_BRANCH" == "master" && "$TRAVIS_RUST_VERSION" == "beta" ]]; then
cargo doc --no-deps && cargo doc --features "alpn, tls, session" --no-deps &&
echo "<meta http-equiv=refresh content=0;url=os_balloon/index.html>" > target/doc/index.html && echo "<meta http-equiv=refresh content=0;url=os_balloon/index.html>" > target/doc/index.html &&
curl -sL https://github.com/rust-lang-nursery/mdBook/releases/download/v0.1.2/mdbook-v0.1.2-x86_64-unknown-linux-gnu.tar.gz | tar xvz -C $HOME/.cargo/bin &&
cd guide && mdbook build -d ../target/doc/guide && cd .. &&
git clone https://github.com/davisp/ghp-import.git && git clone https://github.com/davisp/ghp-import.git &&
./ghp-import/ghp_import.py -n -p -f -m "Documentation upload" -r https://"$GH_TOKEN"@github.com/"$TRAVIS_REPO_SLUG.git" target/doc && ./ghp-import/ghp_import.py -n -p -f -m "Documentation upload" -r https://"$GH_TOKEN"@github.com/"$TRAVIS_REPO_SLUG.git" target/doc &&
echo "Uploaded documentation" echo "Uploaded documentation"
fi fi
- | - |
if [[ "$TRAVIS_OS_NAME" == "linux" && "$TRAVIS_RUST_VERSION" == "stable" ]]; then if [[ "$TRAVIS_OS_NAME" == "linux" && "$TRAVIS_RUST_VERSION" == "nightly" ]]; then
wget https://github.com/SimonKagstrom/kcov/archive/master.tar.gz && bash <(curl https://raw.githubusercontent.com/xd009642/tarpaulin/master/travis-install.sh)
tar xzf master.tar.gz && USE_SKEPTIC=1 cargo tarpaulin --out Xml
cd kcov-master && bash <(curl -s https://codecov.io/bash)
mkdir build &&
cd build &&
cmake .. &&
make &&
make install DESTDIR=../../kcov-build &&
cd ../.. &&
rm -rf kcov-master &&
for file in target/debug/actix_web-*[^\.d]; do mkdir -p "target/cov/$(basename $file)"; ./kcov-build/usr/local/bin/kcov --exclude-pattern=/.cargo,/usr/lib --verify "target/cov/$(basename $file)" "$file"; done &&
for file in target/debug/test_*[^\.d]; do mkdir -p "target/cov/$(basename $file)"; ./kcov-build/usr/local/bin/kcov --exclude-pattern=/.cargo,/usr/lib --verify "target/cov/$(basename $file)" "$file"; done &&
bash <(curl -s https://codecov.io/bash) &&
echo "Uploaded code coverage" echo "Uploaded code coverage"
fi fi

View File

@ -1,4 +1,250 @@
# CHANGES # Changes
## 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
* Gracefull 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) ## 0.2.0 (2017-10-30)

46
CODE_OF_CONDUCT.md Normal file
View File

@ -0,0 +1,46 @@
# Contributor Covenant Code of Conduct
## Our Pledge
In the interest of fostering an open and welcoming environment, we as contributors and maintainers pledge to making participation in our project and our community a harassment-free experience for everyone, regardless of age, body size, disability, ethnicity, gender identity and expression, level of experience, nationality, personal appearance, race, religion, or sexual identity and orientation.
## Our Standards
Examples of behavior that contributes to creating a positive environment include:
* Using welcoming and inclusive language
* Being respectful of differing viewpoints and experiences
* Gracefully accepting constructive criticism
* Focusing on what is best for the community
* Showing empathy towards other community members
Examples of unacceptable behavior by participants include:
* The use of sexualized language or imagery and unwelcome sexual attention or advances
* Trolling, insulting/derogatory comments, and personal or political attacks
* Public or private harassment
* Publishing others' private information, such as a physical or electronic address, without explicit permission
* Other conduct which could reasonably be considered inappropriate in a professional setting
## Our Responsibilities
Project maintainers are responsible for clarifying the standards of acceptable behavior and are expected to take appropriate and fair corrective action in response to any instances of unacceptable behavior.
Project maintainers have the right and responsibility to remove, edit, or reject comments, commits, code, wiki edits, issues, and other contributions that are not aligned to this Code of Conduct, or to ban temporarily or permanently any contributor for other behaviors that they deem inappropriate, threatening, offensive, or harmful.
## Scope
This Code of Conduct applies both within project spaces and in public spaces when an individual is representing the project or its community. Examples of representing a project or community include using an official project e-mail address, posting via an official social media account, or acting as an appointed representative at an online or offline event. Representation of a project may be further defined and clarified by project maintainers.
## Enforcement
Instances of abusive, harassing, or otherwise unacceptable behavior may be reported by contacting the project team at fafhrd91@gmail.com. The project team will review and investigate all complaints, and will respond in a way that it deems appropriate to the circumstances. The project team is obligated to maintain confidentiality with regard to the reporter of an incident. Further details of specific enforcement policies may be posted separately.
Project maintainers who do not follow or enforce the Code of Conduct in good faith may face temporary or permanent repercussions as determined by other members of the project's leadership.
## Attribution
This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 1.4, available at [http://contributor-covenant.org/version/1/4][version]
[homepage]: http://contributor-covenant.org
[version]: http://contributor-covenant.org/version/1/4/

View File

@ -1,16 +1,20 @@
[package] [package]
name = "actix-web" name = "actix-web"
version = "0.2.0" version = "0.5.1"
authors = ["Nikolay Kim <fafhrd91@gmail.com>"] authors = ["Nikolay Kim <fafhrd91@gmail.com>"]
description = "Actix web framework" description = "Actix web is a simple, pragmatic and extremely fast web framework for Rust."
readme = "README.md" readme = "README.md"
keywords = ["actor", "http", "web"] keywords = ["http", "web", "framework", "async", "futures"]
homepage = "https://github.com/actix/actix-web" homepage = "https://github.com/actix/actix-web"
repository = "https://github.com/actix/actix-web.git" repository = "https://github.com/actix/actix-web.git"
documentation = "https://docs.rs/actix-web/" documentation = "https://docs.rs/actix-web/"
categories = ["network-programming", "asynchronous"] categories = ["network-programming", "asynchronous",
license = "Apache-2.0" "web-programming::http-server",
exclude = [".gitignore", ".travis.yml", ".cargo/config", "appveyor.yml"] "web-programming::http-client",
"web-programming::websocket"]
license = "MIT/Apache-2.0"
exclude = [".gitignore", ".travis.yml", ".cargo/config",
"appveyor.yml", "/examples/**"]
build = "build.rs" build = "build.rs"
[badges] [badges]
@ -23,48 +27,104 @@ name = "actix_web"
path = "src/lib.rs" path = "src/lib.rs"
[features] [features]
default = [] default = ["session", "brotli"]
# http/2 # tls
# http2 = ["h2"] tls = ["native-tls", "tokio-tls"]
# openssl
alpn = ["openssl", "tokio-openssl"]
# sessions
session = ["cookie/secure"]
# brotli encoding
brotli = ["brotli2"]
[dependencies] [dependencies]
log = "0.3" actix = "^0.5.5"
time = "0.1"
http = "0.1"
httparse = "0.1"
http-range = "0.1"
mime = "0.3"
mime_guess = "1.8"
cookie = { version="0.10", features=["percent-encode"] }
regex = "0.2"
sha1 = "0.2"
url = "1.5"
percent-encoding = "1.0"
# tokio base64 = "0.9"
bitflags = "1.0"
failure = "0.1.1"
flate2 = "1.0"
h2 = "0.1"
http = "^0.1.5"
httparse = "1.2"
http-range = "0.1"
libc = "0.2"
log = "0.4"
mime = "0.3"
mime_guess = "2.0.0-alpha"
num_cpus = "1.0"
percent-encoding = "1.0"
rand = "0.4"
regex = "0.2"
serde = "1.0"
serde_json = "1.0"
serde_urlencoded = "0.5"
sha1 = "0.6"
smallvec = "0.6"
time = "0.1"
encoding = "0.2"
language-tags = "0.2"
lazy_static = "1.0"
url = { version="1.7", features=["query_encoding"] }
cookie = { version="0.10", features=["percent-encode"] }
brotli2 = { version="^0.3.2", optional = true }
# io
mio = "^0.6.13"
net2 = "0.2"
bytes = "0.4" bytes = "0.4"
byteorder = "1"
futures = "0.1" futures = "0.1"
futures-cpupool = "0.1"
tokio-io = "0.1" tokio-io = "0.1"
tokio-core = "0.1" tokio-core = "0.1"
# h2 = { git = 'https://github.com/carllerche/h2', optional = true } trust-dns-resolver = "0.8"
[dependencies.actix] # native-tls
version = ">=0.3.1" native-tls = { version="0.1", optional = true }
#path = "../actix" tokio-tls = { version="0.1", optional = true }
#git = "https://github.com/actix/actix.git"
default-features = false # openssl
features = [] openssl = { version="0.10", optional = true }
tokio-openssl = { version="0.2", optional = true }
[dev-dependencies] [dev-dependencies]
env_logger = "0.4" env_logger = "0.5"
reqwest = "0.8"
skeptic = "0.13" skeptic = "0.13"
serde_derive = "1.0"
[build-dependencies] [build-dependencies]
skeptic = "0.13" skeptic = "0.13"
version_check = "0.1"
[profile.release] [profile.release]
lto = true lto = true
opt-level = 3 opt-level = 3
debug = true codegen-units = 1
[workspace]
members = [
"./",
"examples/basics",
"examples/juniper",
"examples/diesel",
"examples/r2d2",
"examples/json",
"examples/protobuf",
"examples/hello-world",
"examples/http-proxy",
"examples/multipart",
"examples/state",
"examples/redis-session",
"examples/template_tera",
"examples/tls",
"examples/websocket",
"examples/websocket-chat",
"examples/web-cors/backend",
"examples/unix-socket",
"tools/wsload/",
]

25
LICENSE-MIT Normal file
View File

@ -0,0 +1,25 @@
Copyright (c) 2017 Nikolay Kim
Permission is hereby granted, free of charge, to any
person obtaining a copy of this software and associated
documentation files (the "Software"), to deal in the
Software without restriction, including without
limitation the rights to use, copy, modify, merge,
publish, distribute, sublicense, and/or sell copies of
the Software, and to permit persons to whom the Software
is furnished to do so, subject to the following
conditions:
The above copyright notice and this permission notice
shall be included in all copies or substantial portions
of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF
ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED
TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT
SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR
IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
DEALINGS IN THE SOFTWARE.

30
MIGRATION-0.4-0.5.md Normal file
View File

@ -0,0 +1,30 @@
# Migration from 0.4 to 0.5
* `HttpResponseBuilder::body()`, `.finish()`, `.json()`
methods return `HttpResponse` instead of `Result<HttpResponse>`
* `actix_web::Method`, `actix_web::StatusCode`, `actix_web::Version`
moved to `actix_web::http` module
* `actix_web::header` moved to `actix_web::http::header`
* `NormalizePath` moved to `actix_web::http` module
* `HttpServer` moved to `actix_web::server`, added new `actix_web::server::new()` function,
shortcut for `actix_web::server::HttpServer::new()`
* `DefaultHeaders` middleware does not use separate builder, all builder methods moved to type itself
* `StaticFiles::new()`'s show_index parameter removed, use `show_files_listing()` method instead.
* `CookieSessionBackendBuilder` removed, all methods moved to `CookieSessionBackend` type
* `actix_web::httpcodes` module is deprecated, `HttpResponse::Ok()`, `HttpResponse::Found()` and other `HttpResponse::XXX()`
functions should be used instead
* `ClientRequestBuilder::body()` returns `Result<_, actix_web::Error>`
instead of `Result<_, http::Error>`
* `Application` renamed to a `App`
* `actix_web::Reply`, `actix_web::Resource` moved to `actix_web::dev`

View File

@ -1,6 +1,6 @@
.PHONY: default build test doc clean .PHONY: default build test doc book clean
CARGO_FLAGS := --features "$(FEATURES)" CARGO_FLAGS := --features "$(FEATURES) alpn"
default: test default: test
@ -20,3 +20,7 @@ clippy:
doc: build doc: build
cargo doc --no-deps $(CARGO_FLAGS) cargo doc --no-deps $(CARGO_FLAGS)
cd guide; mdbook build -d ../target/doc/guide/; cd ..
book:
cd guide; mdbook build -d ../target/doc/guide/; cd ..

179
README.md
View File

@ -1,123 +1,86 @@
# Actix web [![Build Status](https://travis-ci.org/actix/actix-web.svg?branch=master)](https://travis-ci.org/actix/actix-web) [![Build status](https://ci.appveyor.com/api/projects/status/kkdb4yce7qhm5w85/branch/master?svg=true)](https://ci.appveyor.com/project/fafhrd91/actix-web-hdy9d/branch/master) [![codecov](https://codecov.io/gh/actix/actix-web/branch/master/graph/badge.svg)](https://codecov.io/gh/actix/actix-web) [![crates.io](http://meritbadge.herokuapp.com/actix-web)](https://crates.io/crates/actix-web) # Actix web [![Build Status](https://travis-ci.org/actix/actix-web.svg?branch=master)](https://travis-ci.org/actix/actix-web) [![Build status](https://ci.appveyor.com/api/projects/status/kkdb4yce7qhm5w85/branch/master?svg=true)](https://ci.appveyor.com/project/fafhrd91/actix-web-hdy9d/branch/master) [![codecov](https://codecov.io/gh/actix/actix-web/branch/master/graph/badge.svg)](https://codecov.io/gh/actix/actix-web) [![crates.io](https://meritbadge.herokuapp.com/actix-web)](https://crates.io/crates/actix-web) [![Join the chat at https://gitter.im/actix/actix](https://badges.gitter.im/actix/actix.svg)](https://gitter.im/actix/actix?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge)
Asynchronous web framework for [Actix](https://github.com/actix/actix). Actix web is a simple, pragmatic and extremely fast web framework for Rust.
* [API Documentation (Development)](http://actix.github.io/actix-web/actix_web/) * Supported *HTTP/1.x* and [*HTTP/2.0*](https://actix.rs/actix-web/guide/qs_13.html) protocols
* Streaming and pipelining
* Keep-alive and slow requests handling
* Client/server [WebSockets](https://actix.rs/actix-web/guide/qs_9.html) support
* Transparent content compression/decompression (br, gzip, deflate)
* Configurable [request routing](https://actix.rs/actix-web/guide/qs_5.html)
* Graceful server shutdown
* Multipart streams
* Static assets
* SSL support with OpenSSL or `native-tls`
* Middlewares ([Logger](https://actix.rs/actix-web/guide/qs_10.html#logging),
[Session](https://actix.rs/actix-web/guide/qs_10.html#user-sessions),
[Redis sessions](https://github.com/actix/actix-redis),
[DefaultHeaders](https://actix.rs/actix-web/guide/qs_10.html#default-headers),
[CORS](https://actix.rs/actix-web/actix_web/middleware/cors/index.html),
[CSRF](https://actix.rs/actix-web/actix_web/middleware/csrf/index.html))
* Built on top of [Actix actor framework](https://github.com/actix/actix)
## Documentation & community resources
* [User Guide](https://actix.github.io/actix-web/guide/)
* [API Documentation (Development)](https://actix.github.io/actix-web/actix_web/)
* [API Documentation (Releases)](https://docs.rs/actix-web/) * [API Documentation (Releases)](https://docs.rs/actix-web/)
* [Chat on gitter](https://gitter.im/actix/actix)
* Cargo package: [actix-web](https://crates.io/crates/actix-web) * Cargo package: [actix-web](https://crates.io/crates/actix-web)
* Minimum supported Rust version: 1.20 or later * Minimum supported Rust version: 1.21 or later
---
Actix web is licensed under the [Apache-2.0 license](http://opensource.org/licenses/APACHE-2.0).
## Features
* HTTP 1.1 and 1.0 support
* Streaming and pipelining support
* Keep-alive and slow requests support
* [WebSockets support](https://actix.github.io/actix-web/actix_web/ws/index.html)
* Configurable request routing
* Multipart streams
* Middlewares
## Usage
To use `actix-web`, add this to your `Cargo.toml`:
```toml
[dependencies]
actix-web = "0.2"
```
## Example ## Example
* [Basic](https://github.com/actix/actix-web/tree/master/examples/basic.rs)
* [Stateful](https://github.com/actix/actix-web/tree/master/examples/state.rs)
* [Mulitpart streams](https://github.com/actix/actix-web/tree/master/examples/multipart)
* [Simple websocket session](https://github.com/actix/actix-web/tree/master/examples/websocket.rs)
* [Tcp/Websocket chat](https://github.com/actix/actix-web/tree/master/examples/websocket-chat)
* [SockJS Server](https://github.com/fafhrd91/actix-sockjs)
```rust ```rust
extern crate actix;
extern crate actix_web; extern crate actix_web;
extern crate env_logger; use actix_web::{http, server, App, Path};
use actix::*; fn index(info: Path<(u32, String)>) -> String {
use actix_web::*; format!("Hello {}! id:{}", info.0, info.1)
struct MyWebSocket;
/// Actor with http context
impl Actor for MyWebSocket {
type Context = HttpContext<Self>;
}
/// Http route handler
impl Route for MyWebSocket {
type State = ();
fn request(req: &mut HttpRequest,
payload: Payload, ctx: &mut HttpContext<Self>) -> RouteResult<Self>
{
// websocket handshake
let resp = ws::handshake(req)?;
// send HttpResponse back to peer
ctx.start(resp);
// convert bytes stream to a stream of `ws::Message` and handle stream
ctx.add_stream(ws::WsStream::new(payload));
Reply::async(MyWebSocket)
}
}
/// Standard actix's stream handler for a stream of `ws::Message`
impl StreamHandler<ws::Message> for MyWebSocket {
fn started(&mut self, ctx: &mut Self::Context) {
println!("WebSocket session openned");
}
fn finished(&mut self, ctx: &mut Self::Context) {
println!("WebSocket session closed");
}
}
impl Handler<ws::Message> for MyWebSocket {
fn handle(&mut self, msg: ws::Message, ctx: &mut HttpContext<Self>)
-> Response<Self, ws::Message>
{
// process websocket messages
println!("WS: {:?}", msg);
match msg {
ws::Message::Ping(msg) => ws::WsWriter::pong(ctx, &msg),
ws::Message::Text(text) => ws::WsWriter::text(ctx, &text),
ws::Message::Binary(bin) => ws::WsWriter::binary(ctx, bin),
ws::Message::Closed | ws::Message::Error => {
ctx.stop();
}
_ => (),
}
Self::empty()
}
} }
fn main() { fn main() {
::std::env::set_var("RUST_LOG", "actix_web=info"); server::new(
let _ = env_logger::init(); || App::new()
let sys = actix::System::new("ws-example"); .route("/{id}/{name}/index.html", http::Method::GET, index))
.bind("127.0.0.1:8080").unwrap()
HttpServer::new( .run();
Application::default("/")
// enable logger
.middleware(Logger::new(None))
// websocket route
.resource("/ws/", |r| r.get::<MyWebSocket>())
.route_handler("/", StaticFiles::new("examples/static/", true)))
.serve::<_, ()>("127.0.0.1:8080").unwrap();
Arbiter::system().send(msgs::SystemExit(0));
let _ = sys.run();
} }
``` ```
### More examples
* [Basics](https://github.com/actix/actix-web/tree/master/examples/basics/)
* [Stateful](https://github.com/actix/actix-web/tree/master/examples/state/)
* [Protobuf support](https://github.com/actix/actix-web/tree/master/examples/protobuf/)
* [Multipart streams](https://github.com/actix/actix-web/tree/master/examples/multipart/)
* [Simple websocket session](https://github.com/actix/actix-web/tree/master/examples/websocket/)
* [Tera templates](https://github.com/actix/actix-web/tree/master/examples/template_tera/)
* [Diesel integration](https://github.com/actix/actix-web/tree/master/examples/diesel/)
* [SSL / HTTP/2.0](https://github.com/actix/actix-web/tree/master/examples/tls/)
* [Tcp/Websocket chat](https://github.com/actix/actix-web/tree/master/examples/websocket-chat/)
* [Json](https://github.com/actix/actix-web/tree/master/examples/json/)
You may consider checking out
[this directory](https://github.com/actix/actix-web/tree/master/examples) for more examples.
## Benchmarks
* [TechEmpower Framework Benchmark](https://www.techempower.com/benchmarks/#section=data-r15&hw=ph&test=plaintext)
* Some basic benchmarks could be found in this [repository](https://github.com/fafhrd91/benchmarks).
## License
This project is licensed under either of
* Apache License, Version 2.0, ([LICENSE-APACHE](LICENSE-APACHE) or [http://www.apache.org/licenses/LICENSE-2.0](http://www.apache.org/licenses/LICENSE-2.0))
* MIT license ([LICENSE-MIT](LICENSE-MIT) or [http://opensource.org/licenses/MIT](http://opensource.org/licenses/MIT))
at your option.
## Code of Conduct
Contribution to the actix-web crate is organized under the terms of the
Contributor Covenant, the maintainer of actix-web, @fafhrd91, promises to
intervene to uphold that code of conduct.

View File

@ -1,18 +1,49 @@
extern crate skeptic; extern crate skeptic;
extern crate version_check;
use std::{env, fs}; use std::{env, fs};
#[cfg(unix)] #[cfg(unix)]
fn main() { fn main() {
println!("cargo:rerun-if-env-changed=USE_SKEPTIC");
let f = env::var("OUT_DIR").unwrap() + "/skeptic-tests.rs";
if env::var("USE_SKEPTIC").is_ok() { if env::var("USE_SKEPTIC").is_ok() {
let _ = fs::remove_file(f);
// generates doc tests for `README.md`. // generates doc tests for `README.md`.
skeptic::generate_doc_tests(&["README.md"]); skeptic::generate_doc_tests(
&[// "README.md",
"guide/src/qs_1.md",
"guide/src/qs_2.md",
"guide/src/qs_3.md",
"guide/src/qs_3_5.md",
"guide/src/qs_4.md",
"guide/src/qs_4_5.md",
"guide/src/qs_5.md",
"guide/src/qs_7.md",
"guide/src/qs_8.md",
"guide/src/qs_9.md",
"guide/src/qs_10.md",
"guide/src/qs_12.md",
"guide/src/qs_13.md",
"guide/src/qs_14.md",
]);
} else { } else {
let f = env::var("OUT_DIR").unwrap() + "/skeptic-tests.rs";
let _ = fs::File::create(f); let _ = fs::File::create(f);
} }
match version_check::is_nightly() {
Some(true) => println!("cargo:rustc-cfg=actix_nightly"),
Some(false) => (),
None => (),
};
} }
#[cfg(not(unix))] #[cfg(not(unix))]
fn main() { fn main() {
match version_check::is_nightly() {
Some(true) => println!("cargo:rustc-cfg=actix_nightly"),
Some(false) => (),
None => (),
};
} }

4
cov.sh
View File

@ -1,4 +0,0 @@
#!/bin/bash
for file in target/debug/actix_web-*[^\.d]; do mkdir -p "target/cov/$(basename $file)"; /usr/local/bin/kcov --exclude-pattern=/.cargo,/usr/lib --verify "target/cov/$(basename $file)" "$file"; done &&
for file in target/debug/test_*[^\.d]; do mkdir -p "target/cov/$(basename $file)"; /usr/local/bin/kcov --exclude-pattern=/.cargo,/usr/lib --verify "target/cov/$(basename $file)" "$file"; done

View File

@ -1,53 +0,0 @@
#![allow(unused_variables)]
extern crate actix;
extern crate actix_web;
extern crate env_logger;
use actix_web::*;
/// somple handle
fn index(req: &mut HttpRequest, _payload: Payload, state: &()) -> HttpResponse {
println!("{:?}", req);
httpcodes::HTTPOk.into()
}
/// handle with path parameters like `/name/{name}/`
fn with_param(req: &mut HttpRequest, _payload: Payload, state: &())
-> HandlerResult<HttpResponse>
{
println!("{:?}", req);
Ok(HttpResponse::builder(StatusCode::OK)
.content_type("test/plain")
.body(format!("Hello {}!", req.match_info().get("name").unwrap()))?)
}
fn main() {
::std::env::set_var("RUST_LOG", "actix_web=info");
let _ = env_logger::init();
let sys = actix::System::new("ws-example");
HttpServer::new(
Application::default("/")
// enable logger
.middleware(Logger::new(None))
// register simple handler, handle all methods
.handler("/index.html", index)
// with path parameters
.resource("/user/{name}/", |r| r.handler(Method::GET, with_param))
// redirect
.resource("/", |r| r.handler(Method::GET, |req, _, _| {
println!("{:?}", req);
Ok(httpcodes::HTTPFound
.builder()
.header("LOCATION", "/index.html")
.body(Body::Empty)?)
}))
// static files
.route_handler("/static", StaticFiles::new("examples/static/", true)))
.serve::<_, ()>("127.0.0.1:8080").unwrap();
println!("Started http server: 127.0.0.1:8080");
let _ = sys.run();
}

View File

@ -0,0 +1,11 @@
[package]
name = "basics"
version = "0.1.0"
authors = ["Nikolay Kim <fafhrd91@gmail.com>"]
workspace = "../.."
[dependencies]
futures = "0.1"
env_logger = "0.5"
actix = "0.5"
actix-web = { path="../.." }

20
examples/basics/README.md Normal file
View File

@ -0,0 +1,20 @@
# basics
## Usage
### server
```bash
cd actix-web/examples/basics
cargo run
# Started http server: 127.0.0.1:8080
```
### web client
- [http://localhost:8080/index.html](http://localhost:8080/index.html)
- [http://localhost:8080/async/bob](http://localhost:8080/async/bob)
- [http://localhost:8080/user/bob/](http://localhost:8080/user/bob/) plain/text download
- [http://localhost:8080/test](http://localhost:8080/test) (return status switch GET or POST or other)
- [http://localhost:8080/static/index.html](http://localhost:8080/static/index.html)
- [http://localhost:8080/static/notexit](http://localhost:8080/static/notexit) display 404 page

136
examples/basics/src/main.rs Normal file
View File

@ -0,0 +1,136 @@
#![allow(unused_variables)]
#![cfg_attr(feature="cargo-clippy", allow(needless_pass_by_value))]
extern crate actix;
extern crate actix_web;
extern crate env_logger;
extern crate futures;
use futures::Stream;
use std::{io, env};
use actix_web::{error, fs, pred, server,
App, HttpRequest, HttpResponse, Result, Error};
use actix_web::http::{header, Method, StatusCode};
use actix_web::middleware::{self, RequestSession};
use futures::future::{FutureResult, result};
/// favicon handler
fn favicon(req: HttpRequest) -> Result<fs::NamedFile> {
Ok(fs::NamedFile::open("../static/favicon.ico")?)
}
/// simple index handler
fn index(mut req: HttpRequest) -> Result<HttpResponse> {
println!("{:?}", req);
// example of ...
if let Ok(ch) = req.poll() {
if let futures::Async::Ready(Some(d)) = ch {
println!("{}", String::from_utf8_lossy(d.as_ref()));
}
}
// session
let mut counter = 1;
if let Some(count) = req.session().get::<i32>("counter")? {
println!("SESSION value: {}", count);
counter = count + 1;
req.session().set("counter", counter)?;
} else {
req.session().set("counter", counter)?;
}
// response
Ok(HttpResponse::build(StatusCode::OK)
.content_type("text/html; charset=utf-8")
.body(include_str!("../static/welcome.html")))
}
/// 404 handler
fn p404(req: HttpRequest) -> Result<fs::NamedFile> {
Ok(fs::NamedFile::open("./static/404.html")?
.set_status_code(StatusCode::NOT_FOUND))
}
/// async handler
fn index_async(req: HttpRequest) -> FutureResult<HttpResponse, Error>
{
println!("{:?}", req);
result(Ok(HttpResponse::Ok()
.content_type("text/html")
.body(format!("Hello {}!", req.match_info().get("name").unwrap()))))
}
/// handler with path parameters like `/user/{name}/`
fn with_param(req: HttpRequest) -> HttpResponse
{
println!("{:?}", req);
HttpResponse::Ok()
.content_type("test/plain")
.body(format!("Hello {}!", req.match_info().get("name").unwrap()))
}
fn main() {
env::set_var("RUST_LOG", "actix_web=debug");
env::set_var("RUST_BACKTRACE", "1");
env_logger::init();
let sys = actix::System::new("basic-example");
let addr = server::new(
|| App::new()
// enable logger
.middleware(middleware::Logger::default())
// cookie session middleware
.middleware(middleware::SessionStorage::new(
middleware::CookieSessionBackend::signed(&[0; 32]).secure(false)
))
// register favicon
.resource("/favicon.ico", |r| r.f(favicon))
// register simple route, handle all methods
.resource("/index.html", |r| r.f(index))
// with path parameters
.resource("/user/{name}/", |r| r.method(Method::GET).f(with_param))
// async handler
.resource("/async/{name}", |r| r.method(Method::GET).a(index_async))
.resource("/test", |r| r.f(|req| {
match *req.method() {
Method::GET => HttpResponse::Ok(),
Method::POST => HttpResponse::MethodNotAllowed(),
_ => HttpResponse::NotFound(),
}
}))
.resource("/error.html", |r| r.f(|req| {
error::InternalError::new(
io::Error::new(io::ErrorKind::Other, "test"), StatusCode::OK)
}))
// static files
.handler("/static/", fs::StaticFiles::new("../static/"))
// redirect
.resource("/", |r| r.method(Method::GET).f(|req| {
println!("{:?}", req);
HttpResponse::Found()
.header(header::LOCATION, "/index.html")
.finish()
}))
// default
.default_resource(|r| {
// 404 for GET request
r.method(Method::GET).f(p404);
// all requests that are not `GET`
r.route().filter(pred::Not(pred::Get())).f(
|req| HttpResponse::MethodNotAllowed());
}))
.bind("127.0.0.1:8080").expect("Can not bind to 127.0.0.1:8080")
.shutdown_timeout(0) // <- Set shutdown timeout to 0 seconds (default 60s)
.start();
println!("Starting http server: 127.0.0.1:8080");
let _ = sys.run();
}

View File

@ -0,0 +1,7 @@
<!DOCTYPE html><html><head><title>actix - basics</title>
<link rel="shortcut icon" type="image/x-icon" href="/favicon.ico" /></head>
<body>
<a href="index.html">back to home</a>
<h1>404</h1>
</body>
</html>

View File

@ -0,0 +1,6 @@
<!DOCTYPE html><html><head><title>actix - basics</title>
<link rel="shortcut icon" type="image/x-icon" href="/favicon.ico" /></head>
<body>
<h1>Welcome <img width="30px" height="30px" src="/static/actixLogo.png" /></h1>
</body>
</html>

1
examples/diesel/.env Normal file
View File

@ -0,0 +1 @@
DATABASE_URL=file:test.db

View File

@ -0,0 +1,20 @@
[package]
name = "diesel-example"
version = "0.1.0"
authors = ["Nikolay Kim <fafhrd91@gmail.com>"]
workspace = "../.."
[dependencies]
env_logger = "0.5"
actix = "0.5"
actix-web = { path = "../../" }
futures = "0.1"
uuid = { version = "0.5", features = ["serde", "v4"] }
serde = "1.0"
serde_json = "1.0"
serde_derive = "1.0"
diesel = { version = "^1.1.0", features = ["sqlite", "r2d2"] }
r2d2 = "0.8"
dotenv = "0.10"

43
examples/diesel/README.md Normal file
View File

@ -0,0 +1,43 @@
# diesel
Diesel's `Getting Started` guide using SQLite for Actix web
## Usage
### init database sqlite
```bash
cargo install diesel_cli --no-default-features --features sqlite
cd actix-web/examples/diesel
echo "DATABASE_URL=file:test.db" > .env
diesel migration run
```
### server
```bash
# if ubuntu : sudo apt-get install libsqlite3-dev
# if fedora : sudo dnf install libsqlite3x-devel
cd actix-web/examples/diesel
cargo run (or ``cargo watch -x run``)
# Started http server: 127.0.0.1:8080
```
### web client
[http://127.0.0.1:8080/NAME](http://127.0.0.1:8080/NAME)
### sqlite client
```bash
# if ubuntu : sudo apt-get install sqlite3
# if fedora : sudo dnf install sqlite3x
sqlite3 test.db
sqlite> .tables
sqlite> select * from users;
```
## Postgresql
You will also find another complete example of diesel+postgresql on [https://github.com/TechEmpower/FrameworkBenchmarks/tree/master/frameworks/Rust/actix](https://github.com/TechEmpower/FrameworkBenchmarks/tree/master/frameworks/Rust/actix)

View File

@ -0,0 +1 @@
DROP TABLE users

View File

@ -0,0 +1,4 @@
CREATE TABLE users (
id VARCHAR NOT NULL PRIMARY KEY,
name VARCHAR NOT NULL
)

55
examples/diesel/src/db.rs Normal file
View File

@ -0,0 +1,55 @@
//! Db executor actor
use uuid;
use diesel;
use actix_web::*;
use actix::prelude::*;
use diesel::prelude::*;
use diesel::r2d2::{Pool, ConnectionManager};
use models;
use schema;
/// This is db executor actor. We are going to run 3 of them in parallel.
pub struct DbExecutor(pub Pool<ConnectionManager<SqliteConnection>>);
/// This is only message that this actor can handle, but it is easy to extend number of
/// messages.
pub struct CreateUser {
pub name: String,
}
impl Message for CreateUser {
type Result = Result<models::User, Error>;
}
impl Actor for DbExecutor {
type Context = SyncContext<Self>;
}
impl Handler<CreateUser> for DbExecutor {
type Result = Result<models::User, Error>;
fn handle(&mut self, msg: CreateUser, _: &mut Self::Context) -> Self::Result {
use self::schema::users::dsl::*;
let uuid = format!("{}", uuid::Uuid::new_v4());
let new_user = models::NewUser {
id: &uuid,
name: &msg.name,
};
let conn: &SqliteConnection = &self.0.get().unwrap();
diesel::insert_into(users)
.values(&new_user)
.execute(conn)
.expect("Error inserting person");
let mut items = users
.filter(id.eq(&uuid))
.load::<models::User>(conn)
.expect("Error loading person");
Ok(items.pop().unwrap())
}
}

View File

@ -0,0 +1,78 @@
//! Actix web diesel example
//!
//! Diesel does not support tokio, so we have to run it in separate threads.
//! Actix supports sync actors by default, so we going to create sync actor that use diesel.
//! Technically sync actors are worker style actors, multiple of them
//! can run in parallel and process messages from same queue.
extern crate serde;
extern crate serde_json;
#[macro_use]
extern crate serde_derive;
#[macro_use]
extern crate diesel;
extern crate r2d2;
extern crate uuid;
extern crate futures;
extern crate actix;
extern crate actix_web;
extern crate env_logger;
use actix::prelude::*;
use actix_web::{http, server, middleware,
App, Path, State, HttpResponse, AsyncResponder, FutureResponse};
use diesel::prelude::*;
use diesel::r2d2::{ Pool, ConnectionManager };
use futures::future::Future;
mod db;
mod models;
mod schema;
use db::{CreateUser, DbExecutor};
/// State with DbExecutor address
struct AppState {
db: Addr<Syn, DbExecutor>,
}
/// Async request handler
fn index(name: Path<String>, state: State<AppState>) -> FutureResponse<HttpResponse> {
// send async `CreateUser` message to a `DbExecutor`
state.db.send(CreateUser{name: name.into_inner()})
.from_err()
.and_then(|res| {
match res {
Ok(user) => Ok(HttpResponse::Ok().json(user)),
Err(_) => Ok(HttpResponse::InternalServerError().into())
}
})
.responder()
}
fn main() {
::std::env::set_var("RUST_LOG", "actix_web=info");
env_logger::init();
let sys = actix::System::new("diesel-example");
// Start 3 db executor actors
let manager = ConnectionManager::<SqliteConnection>::new("test.db");
let pool = r2d2::Pool::builder().build(manager).expect("Failed to create pool.");
let addr = SyncArbiter::start(3, move || {
DbExecutor(pool.clone())
});
// Start http server
server::new(move || {
App::with_state(AppState{db: addr.clone()})
// enable logger
.middleware(middleware::Logger::default())
.resource("/{name}", |r| r.method(http::Method::GET).with2(index))})
.bind("127.0.0.1:8080").unwrap()
.start();
println!("Started http server: 127.0.0.1:8080");
let _ = sys.run();
}

View File

@ -0,0 +1,14 @@
use super::schema::users;
#[derive(Serialize, Queryable)]
pub struct User {
pub id: String,
pub name: String,
}
#[derive(Insertable)]
#[table_name = "users"]
pub struct NewUser<'a> {
pub id: &'a str,
pub name: &'a str,
}

View File

@ -0,0 +1,6 @@
table! {
users (id) {
id -> Text,
name -> Text,
}
}

BIN
examples/diesel/test.db Normal file

Binary file not shown.

View File

@ -0,0 +1,10 @@
[package]
name = "hello-world"
version = "0.1.0"
authors = ["Nikolay Kim <fafhrd91@gmail.com>"]
workspace = "../.."
[dependencies]
env_logger = "0.5"
actix = "0.5"
actix-web = { path = "../../" }

View File

@ -0,0 +1,28 @@
extern crate actix;
extern crate actix_web;
extern crate env_logger;
use actix_web::{App, HttpRequest, server, middleware};
fn index(_req: HttpRequest) -> &'static str {
"Hello world!"
}
fn main() {
::std::env::set_var("RUST_LOG", "actix_web=info");
env_logger::init();
let sys = actix::System::new("hello-world");
server::new(
|| App::new()
// enable logger
.middleware(middleware::Logger::default())
.resource("/index.html", |r| r.f(|_| "Hello world!"))
.resource("/", |r| r.f(index)))
.bind("127.0.0.1:8080").unwrap()
.start();
println!("Started http server: 127.0.0.1:8080");
let _ = sys.run();
}

View File

@ -0,0 +1,11 @@
[package]
name = "http-proxy"
version = "0.1.0"
authors = ["Nikolay Kim <fafhrd91@gmail.com>"]
workspace = "../.."
[dependencies]
env_logger = "0.5"
futures = "0.1"
actix = "0.5"
actix-web = { path = "../../", features=["alpn"] }

View File

@ -0,0 +1,58 @@
extern crate actix;
extern crate actix_web;
extern crate futures;
extern crate env_logger;
use futures::{Future, Stream};
use actix_web::{
client, server, middleware,
App, AsyncResponder, Body, HttpRequest, HttpResponse, HttpMessage, Error};
/// Stream client request response and then send body to a server response
fn index(_req: HttpRequest) -> Box<Future<Item=HttpResponse, Error=Error>> {
client::ClientRequest::get("https://www.rust-lang.org/en-US/")
.finish().unwrap()
.send()
.map_err(Error::from) // <- convert SendRequestError to an Error
.and_then(
|resp| resp.body() // <- this is MessageBody type, resolves to complete body
.from_err() // <- convert PayloadError to a Error
.and_then(|body| { // <- we got complete body, now send as server response
Ok(HttpResponse::Ok().body(body))
}))
.responder()
}
/// streaming client request to a streaming server response
fn streaming(_req: HttpRequest) -> Box<Future<Item=HttpResponse, Error=Error>> {
// send client request
client::ClientRequest::get("https://www.rust-lang.org/en-US/")
.finish().unwrap()
.send() // <- connect to host and send request
.map_err(Error::from) // <- convert SendRequestError to an Error
.and_then(|resp| { // <- we received client response
Ok(HttpResponse::Ok()
// read one chunk from client response and send this chunk to a server response
// .from_err() converts PayloadError to a Error
.body(Body::Streaming(Box::new(resp.from_err()))))
})
.responder()
}
fn main() {
::std::env::set_var("RUST_LOG", "actix_web=info");
env_logger::init();
let sys = actix::System::new("http-proxy");
server::new(
|| App::new()
.middleware(middleware::Logger::default())
.resource("/streaming", |r| r.f(streaming))
.resource("/", |r| r.f(index)))
.bind("127.0.0.1:8080").unwrap()
.start();
println!("Started http server: 127.0.0.1:8080");
let _ = sys.run();
}

18
examples/json/Cargo.toml Normal file
View File

@ -0,0 +1,18 @@
[package]
name = "json-example"
version = "0.1.0"
authors = ["Nikolay Kim <fafhrd91@gmail.com>"]
workspace = "../.."
[dependencies]
bytes = "0.4"
futures = "0.1"
env_logger = "*"
serde = "1.0"
serde_json = "1.0"
serde_derive = "1.0"
json = "*"
actix = "0.5"
actix-web = { path="../../" }

48
examples/json/README.md Normal file
View File

@ -0,0 +1,48 @@
# json
Json's `Getting Started` guide using json (serde-json or json-rust) for Actix web
## Usage
### server
```bash
cd actix-web/examples/json
cargo run
# Started http server: 127.0.0.1:8080
```
### web client
With [Postman](https://www.getpostman.com/) or [Rested](moz-extension://60daeb1c-5b1b-4afd-9842-0579ed34dfcb/dist/index.html)
- POST / (embed serde-json):
- method : ``POST``
- url : ``http://127.0.0.1:8080/``
- header : ``Content-Type`` = ``application/json``
- body (raw) : ``{"name": "Test user", "number": 100}``
- POST /manual (manual serde-json):
- method : ``POST``
- url : ``http://127.0.0.1:8080/manual``
- header : ``Content-Type`` = ``application/json``
- body (raw) : ``{"name": "Test user", "number": 100}``
- POST /mjsonrust (manual json-rust):
- method : ``POST``
- url : ``http://127.0.0.1:8080/mjsonrust``
- header : ``Content-Type`` = ``application/json``
- body (raw) : ``{"name": "Test user", "number": 100}`` (you can also test ``{notjson}``)
### python client
- ``pip install aiohttp``
- ``python client.py``
if ubuntu :
- ``pip3 install aiohttp``
- ``python3 client.py``

18
examples/json/client.py Normal file
View File

@ -0,0 +1,18 @@
# This script could be used for actix-web multipart example test
# just start server and run client.py
import json
import asyncio
import aiohttp
async def req():
resp = await aiohttp.ClientSession().request(
"post", 'http://localhost:8080/',
data=json.dumps({"name": "Test user", "number": 100}),
headers={"content-type": "application/json"})
print(str(resp))
print(await resp.text())
assert 200 == resp.status
asyncio.get_event_loop().run_until_complete(req())

110
examples/json/src/main.rs Normal file
View File

@ -0,0 +1,110 @@
extern crate actix;
extern crate actix_web;
extern crate bytes;
extern crate futures;
extern crate env_logger;
extern crate serde_json;
#[macro_use] extern crate serde_derive;
#[macro_use] extern crate json;
use actix_web::{
middleware, http, error, server,
App, AsyncResponder, HttpRequest, HttpResponse, HttpMessage, Error, Json};
use bytes::BytesMut;
use futures::{Future, Stream};
use json::JsonValue;
#[derive(Debug, Serialize, Deserialize)]
struct MyObj {
name: String,
number: i32,
}
/// This handler uses `HttpRequest::json()` for loading json object.
fn index(req: HttpRequest) -> Box<Future<Item=HttpResponse, Error=Error>> {
req.json()
.from_err() // convert all errors into `Error`
.and_then(|val: MyObj| {
println!("model: {:?}", val);
Ok(HttpResponse::Ok().json(val)) // <- send response
})
.responder()
}
/// This handler uses json extractor
fn extract_item(item: Json<MyObj>) -> HttpResponse {
println!("model: {:?}", &item);
HttpResponse::Ok().json(item.0) // <- send response
}
const MAX_SIZE: usize = 262_144; // max payload size is 256k
/// This handler manually load request payload and parse json object
fn index_manual(req: HttpRequest) -> Box<Future<Item=HttpResponse, Error=Error>> {
// HttpRequest is stream of Bytes objects
req
// `Future::from_err` acts like `?` in that it coerces the error type from
// the future into the final error type
.from_err()
// `fold` will asynchronously read each chunk of the request body and
// call supplied closure, then it resolves to result of closure
.fold(BytesMut::new(), move |mut body, chunk| {
// limit max size of in-memory payload
if (body.len() + chunk.len()) > MAX_SIZE {
Err(error::ErrorBadRequest("overflow"))
} else {
body.extend_from_slice(&chunk);
Ok(body)
}
})
// `Future::and_then` can be used to merge an asynchronous workflow with a
// synchronous workflow
.and_then(|body| {
// body is loaded, now we can deserialize serde-json
let obj = serde_json::from_slice::<MyObj>(&body)?;
Ok(HttpResponse::Ok().json(obj)) // <- send response
})
.responder()
}
/// This handler manually load request payload and parse json-rust
fn index_mjsonrust(req: HttpRequest) -> Box<Future<Item=HttpResponse, Error=Error>> {
req.concat2()
.from_err()
.and_then(|body| {
// body is loaded, now we can deserialize json-rust
let result = json::parse(std::str::from_utf8(&body).unwrap()); // return Result
let injson: JsonValue = match result { Ok(v) => v, Err(e) => object!{"err" => e.to_string() } };
Ok(HttpResponse::Ok()
.content_type("application/json")
.body(injson.dump()))
})
.responder()
}
fn main() {
::std::env::set_var("RUST_LOG", "actix_web=info");
env_logger::init();
let sys = actix::System::new("json-example");
server::new(|| {
App::new()
// enable logger
.middleware(middleware::Logger::default())
.resource("/extractor", |r| {
r.method(http::Method::POST)
.with(extract_item)
.limit(4096); // <- limit size of the payload
})
.resource("/manual", |r| r.method(http::Method::POST).f(index_manual))
.resource("/mjsonrust", |r| r.method(http::Method::POST).f(index_mjsonrust))
.resource("/", |r| r.method(http::Method::POST).f(index))})
.bind("127.0.0.1:8080").unwrap()
.shutdown_timeout(1)
.start();
println!("Started http server: 127.0.0.1:8080");
let _ = sys.run();
}

View File

@ -0,0 +1,17 @@
[package]
name = "juniper-example"
version = "0.1.0"
authors = ["pyros2097 <pyros2097@gmail.com>"]
workspace = "../.."
[dependencies]
env_logger = "0.5"
actix = "0.5"
actix-web = { path = "../../" }
futures = "0.1"
serde = "1.0"
serde_json = "1.0"
serde_derive = "1.0"
juniper = "0.9.2"

View File

@ -0,0 +1,15 @@
# juniper
Juniper integration for Actix web
### server
```bash
cd actix-web/examples/juniper
cargo run (or ``cargo watch -x run``)
# Started http server: 127.0.0.1:8080
```
### web client
[http://127.0.0.1:8080/graphiql](http://127.0.0.1:8080/graphiql)

View File

@ -0,0 +1,108 @@
//! Actix web juniper example
//!
//! A simple example integrating juniper in actix-web
extern crate serde;
extern crate serde_json;
#[macro_use]
extern crate serde_derive;
#[macro_use]
extern crate juniper;
extern crate futures;
extern crate actix;
extern crate actix_web;
extern crate env_logger;
use actix::prelude::*;
use actix_web::{
middleware, http, server,
App, AsyncResponder, HttpRequest, HttpResponse, FutureResponse, Error, State, Json};
use juniper::http::graphiql::graphiql_source;
use juniper::http::GraphQLRequest;
use futures::future::Future;
mod schema;
use schema::Schema;
use schema::create_schema;
struct AppState {
executor: Addr<Syn, GraphQLExecutor>,
}
#[derive(Serialize, Deserialize)]
pub struct GraphQLData(GraphQLRequest);
impl Message for GraphQLData {
type Result = Result<String, Error>;
}
pub struct GraphQLExecutor {
schema: std::sync::Arc<Schema>
}
impl GraphQLExecutor {
fn new(schema: std::sync::Arc<Schema>) -> GraphQLExecutor {
GraphQLExecutor {
schema: schema,
}
}
}
impl Actor for GraphQLExecutor {
type Context = SyncContext<Self>;
}
impl Handler<GraphQLData> for GraphQLExecutor {
type Result = Result<String, Error>;
fn handle(&mut self, msg: GraphQLData, _: &mut Self::Context) -> Self::Result {
let res = msg.0.execute(&self.schema, &());
let res_text = serde_json::to_string(&res)?;
Ok(res_text)
}
}
fn graphiql(_req: HttpRequest<AppState>) -> Result<HttpResponse, Error> {
let html = graphiql_source("http://127.0.0.1:8080/graphql");
Ok(HttpResponse::Ok()
.content_type("text/html; charset=utf-8")
.body(html))
}
fn graphql(st: State<AppState>, data: Json<GraphQLData>) -> FutureResponse<HttpResponse> {
st.executor.send(data.0)
.from_err()
.and_then(|res| {
match res {
Ok(user) => Ok(HttpResponse::Ok()
.content_type("application/json")
.body(user)),
Err(_) => Ok(HttpResponse::InternalServerError().into())
}
})
.responder()
}
fn main() {
::std::env::set_var("RUST_LOG", "actix_web=info");
env_logger::init();
let sys = actix::System::new("juniper-example");
let schema = std::sync::Arc::new(create_schema());
let addr = SyncArbiter::start(3, move || {
GraphQLExecutor::new(schema.clone())
});
// Start http server
server::new(move || {
App::with_state(AppState{executor: addr.clone()})
// enable logger
.middleware(middleware::Logger::default())
.resource("/graphql", |r| r.method(http::Method::POST).with2(graphql))
.resource("/graphiql", |r| r.method(http::Method::GET).h(graphiql))})
.bind("127.0.0.1:8080").unwrap()
.start();
println!("Started http server: 127.0.0.1:8080");
let _ = sys.run();
}

View File

@ -0,0 +1,58 @@
use juniper::FieldResult;
use juniper::RootNode;
#[derive(GraphQLEnum)]
enum Episode {
NewHope,
Empire,
Jedi,
}
#[derive(GraphQLObject)]
#[graphql(description = "A humanoid creature in the Star Wars universe")]
struct Human {
id: String,
name: String,
appears_in: Vec<Episode>,
home_planet: String,
}
#[derive(GraphQLInputObject)]
#[graphql(description = "A humanoid creature in the Star Wars universe")]
struct NewHuman {
name: String,
appears_in: Vec<Episode>,
home_planet: String,
}
pub struct QueryRoot;
graphql_object!(QueryRoot: () |&self| {
field human(&executor, id: String) -> FieldResult<Human> {
Ok(Human{
id: "1234".to_owned(),
name: "Luke".to_owned(),
appears_in: vec![Episode::NewHope],
home_planet: "Mars".to_owned(),
})
}
});
pub struct MutationRoot;
graphql_object!(MutationRoot: () |&self| {
field createHuman(&executor, new_human: NewHuman) -> FieldResult<Human> {
Ok(Human{
id: "1234".to_owned(),
name: new_human.name,
appears_in: new_human.appears_in,
home_planet: new_human.home_planet,
})
}
});
pub type Schema = RootNode<'static, QueryRoot, MutationRoot>;
pub fn create_schema() -> Schema {
Schema::new(QueryRoot {}, MutationRoot {})
}

View File

@ -2,6 +2,7 @@
name = "multipart-example" name = "multipart-example"
version = "0.1.0" version = "0.1.0"
authors = ["Nikolay Kim <fafhrd91@gmail.com>"] authors = ["Nikolay Kim <fafhrd91@gmail.com>"]
workspace = "../.."
[[bin]] [[bin]]
name = "multipart" name = "multipart"
@ -9,6 +10,6 @@ path = "src/main.rs"
[dependencies] [dependencies]
env_logger = "*" env_logger = "*"
#actix = "0.3" futures = "0.1"
actix = { git = "https://github.com/actix/actix.git" } actix = "0.5"
actix-web = { path = "../../" } actix-web = { path="../../" }

View File

@ -0,0 +1,24 @@
# multipart
Multipart's `Getting Started` guide for Actix web
## Usage
### server
```bash
cd actix-web/examples/multipart
cargo run (or ``cargo watch -x run``)
# Started http server: 127.0.0.1:8080
```
### client
- ``pip install aiohttp``
- ``python client.py``
- you must see in server console multipart fields
if ubuntu :
- ``pip3 install aiohttp``
- ``python3 client.py``

View File

@ -1,26 +1,28 @@
# This script could be used for actix-web multipart example test
# just start server and run client.py
import asyncio import asyncio
import aiohttp import aiohttp
async def req1():
def req1():
with aiohttp.MultipartWriter() as writer: with aiohttp.MultipartWriter() as writer:
writer.append('test') writer.append('test')
writer.append_json({'passed': True}) writer.append_json({'passed': True})
resp = yield from aiohttp.request( resp = await aiohttp.ClientSession().request(
"post", 'http://localhost:8080/multipart', "post", 'http://localhost:8080/multipart',
data=writer, headers=writer.headers) data=writer, headers=writer.headers)
print(resp) print(resp)
assert 200 == resp.status assert 200 == resp.status
def req2(): async def req2():
with aiohttp.MultipartWriter() as writer: with aiohttp.MultipartWriter() as writer:
writer.append('test') writer.append('test')
writer.append_json({'passed': True}) writer.append_json({'passed': True})
writer.append(open('src/main.rs')) writer.append(open('src/main.rs'))
resp = yield from aiohttp.request( resp = await aiohttp.ClientSession().request(
"post", 'http://localhost:8080/multipart', "post", 'http://localhost:8080/multipart',
data=writer, headers=writer.headers) data=writer, headers=writer.headers)
print(resp) print(resp)

View File

@ -2,77 +2,60 @@
extern crate actix; extern crate actix;
extern crate actix_web; extern crate actix_web;
extern crate env_logger; extern crate env_logger;
extern crate futures;
use actix::*; use actix::*;
use actix_web::*; use actix_web::{
http, middleware, multipart, server,
App, AsyncResponder, HttpRequest, HttpResponse, HttpMessage, Error};
struct MyRoute; use futures::{Future, Stream};
use futures::future::{result, Either};
impl Actor for MyRoute {
type Context = HttpContext<Self>;
}
impl Route for MyRoute { fn index(req: HttpRequest) -> Box<Future<Item=HttpResponse, Error=Error>>
type State = (); {
println!("{:?}", req);
fn request(req: &mut HttpRequest, payload: Payload, req.multipart() // <- get multipart stream for current request
ctx: &mut HttpContext<Self>) -> RouteResult<Self> { .from_err() // <- convert multipart errors
println!("{:?}", req); .and_then(|item| { // <- iterate over multipart items
match item {
// Handle multipart Field
multipart::MultipartItem::Field(field) => {
println!("==== FIELD ==== {:?}", field);
let multipart = req.multipart(payload)?; // Field in turn is stream of *Bytes* object
Either::A(
// get Multipart stream field.map_err(Error::from)
WrapStream::<MyRoute>::actstream(multipart) .map(|chunk| {
.and_then(|item, act, ctx| { println!("-- CHUNK: \n{}",
// Multipart stream is a stream of Fields and nested Multiparts std::str::from_utf8(&chunk).unwrap());})
match item { .finish())
multipart::MultipartItem::Field(field) => { },
println!("==== FIELD ==== {:?}", field); multipart::MultipartItem::Nested(mp) => {
// Or item could be nested Multipart stream
// Read field's stream Either::B(result(Ok(())))
fut::Either::A(
field.actstream()
.map(|chunk, act, ctx| {
println!(
"-- CHUNK: \n{}",
std::str::from_utf8(&chunk.0).unwrap());
})
.finish())
},
multipart::MultipartItem::Nested(mp) => {
// Do nothing for nested multipart stream
fut::Either::B(fut::ok(()))
}
} }
}) }
// wait until stream finish })
.finish() .finish() // <- Stream::finish() combinator from actix
.map_err(|e, act, ctx| { .map(|_| HttpResponse::Ok().into())
ctx.start(httpcodes::HTTPBadRequest); .responder()
ctx.write_eof();
})
.map(|_, act, ctx| {
ctx.start(httpcodes::HTTPOk);
ctx.write_eof();
})
.spawn(ctx);
Reply::async(MyRoute)
}
} }
fn main() { fn main() {
::std::env::set_var("RUST_LOG", "actix_web=info");
let _ = env_logger::init(); let _ = env_logger::init();
let sys = actix::System::new("multipart-example"); let sys = actix::System::new("multipart-example");
HttpServer::new( server::new(
vec![ || App::new()
Application::default("/") .middleware(middleware::Logger::default()) // <- logger
.resource("/multipart", |r| { .resource("/multipart", |r| r.method(http::Method::POST).a(index)))
r.post::<MyRoute>(); .bind("127.0.0.1:8080").unwrap()
}).finish() .start();
])
.serve::<_, ()>("127.0.0.1:8080").unwrap();
println!("Starting http server: 127.0.0.1:8080");
let _ = sys.run(); let _ = sys.run();
} }

View File

@ -0,0 +1,16 @@
[package]
name = "protobuf-example"
version = "0.1.0"
authors = ["kingxsp <jin_hb_zh@126.com>"]
[dependencies]
bytes = "0.4"
futures = "0.1"
failure = "0.1"
env_logger = "*"
prost = "0.2.0"
prost-derive = "0.2.0"
actix = "0.5"
actix-web = { path="../../" }

View File

@ -0,0 +1,66 @@
# just start server and run client.py
# wget https://github.com/google/protobuf/releases/download/v3.5.1/protobuf-python-3.5.1.zip
# unzip protobuf-python-3.5.1.zip.1
# cd protobuf-3.5.1/python/
# python3.6 setup.py install
# pip3.6 install --upgrade pip
# pip3.6 install aiohttp
#!/usr/bin/env python
import test_pb2
import traceback
import sys
import asyncio
import aiohttp
def op():
try:
obj = test_pb2.MyObj()
obj.number = 9
obj.name = 'USB'
#Serialize
sendDataStr = obj.SerializeToString()
#print serialized string value
print('serialized string:', sendDataStr)
#------------------------#
# message transmission #
#------------------------#
receiveDataStr = sendDataStr
receiveData = test_pb2.MyObj()
#Deserialize
receiveData.ParseFromString(receiveDataStr)
print('pares serialize string, return: devId = ', receiveData.number, ', name = ', receiveData.name)
except(Exception, e):
print(Exception, ':', e)
print(traceback.print_exc())
errInfo = sys.exc_info()
print(errInfo[0], ':', errInfo[1])
async def fetch(session):
obj = test_pb2.MyObj()
obj.number = 9
obj.name = 'USB'
async with session.post('http://localhost:8080/', data=obj.SerializeToString(),
headers={"content-type": "application/protobuf"}) as resp:
print(resp.status)
data = await resp.read()
receiveObj = test_pb2.MyObj()
receiveObj.ParseFromString(data)
print(receiveObj)
async def go(loop):
obj = test_pb2.MyObj()
obj.number = 9
obj.name = 'USB'
async with aiohttp.ClientSession(loop=loop) as session:
await fetch(session)
loop = asyncio.get_event_loop()
loop.run_until_complete(go(loop))
loop.close()

View File

@ -0,0 +1,57 @@
extern crate actix;
extern crate actix_web;
extern crate bytes;
extern crate futures;
#[macro_use]
extern crate failure;
extern crate env_logger;
extern crate prost;
#[macro_use]
extern crate prost_derive;
use futures::Future;
use actix_web::{
http, middleware, server,
App, AsyncResponder, HttpRequest, HttpResponse, Error};
mod protobuf;
use protobuf::ProtoBufResponseBuilder;
#[derive(Clone, Debug, PartialEq, Message)]
pub struct MyObj {
#[prost(int32, tag="1")]
pub number: i32,
#[prost(string, tag="2")]
pub name: String,
}
/// This handler uses `ProtoBufMessage` for loading protobuf object.
fn index(req: HttpRequest) -> Box<Future<Item=HttpResponse, Error=Error>> {
protobuf::ProtoBufMessage::new(req)
.from_err() // convert all errors into `Error`
.and_then(|val: MyObj| {
println!("model: {:?}", val);
Ok(HttpResponse::Ok().protobuf(val)?) // <- send response
})
.responder()
}
fn main() {
::std::env::set_var("RUST_LOG", "actix_web=info");
env_logger::init();
let sys = actix::System::new("protobuf-example");
server::new(|| {
App::new()
.middleware(middleware::Logger::default())
.resource("/", |r| r.method(http::Method::POST).f(index))})
.bind("127.0.0.1:8080").unwrap()
.shutdown_timeout(1)
.start();
println!("Started http server: 127.0.0.1:8080");
let _ = sys.run();
}

View File

@ -0,0 +1,168 @@
use bytes::{Bytes, BytesMut};
use futures::{Poll, Future, Stream};
use bytes::IntoBuf;
use prost::Message;
use prost::DecodeError as ProtoBufDecodeError;
use prost::EncodeError as ProtoBufEncodeError;
use actix_web::http::header::{CONTENT_TYPE, CONTENT_LENGTH};
use actix_web::{Responder, HttpMessage, HttpRequest, HttpResponse};
use actix_web::dev::HttpResponseBuilder;
use actix_web::error::{Error, PayloadError, ResponseError};
#[derive(Fail, Debug)]
pub enum ProtoBufPayloadError {
/// Payload size is bigger than 256k
#[fail(display="Payload size is bigger than 256k")]
Overflow,
/// Content type error
#[fail(display="Content type error")]
ContentType,
/// Serialize error
#[fail(display="ProtoBud serialize error: {}", _0)]
Serialize(#[cause] ProtoBufEncodeError),
/// Deserialize error
#[fail(display="ProtoBud deserialize error: {}", _0)]
Deserialize(#[cause] ProtoBufDecodeError),
/// Payload error
#[fail(display="Error that occur during reading payload: {}", _0)]
Payload(#[cause] PayloadError),
}
impl ResponseError for ProtoBufPayloadError {
fn error_response(&self) -> HttpResponse {
match *self {
ProtoBufPayloadError::Overflow => HttpResponse::PayloadTooLarge().into(),
_ => HttpResponse::BadRequest().into(),
}
}
}
impl From<PayloadError> for ProtoBufPayloadError {
fn from(err: PayloadError) -> ProtoBufPayloadError {
ProtoBufPayloadError::Payload(err)
}
}
impl From<ProtoBufDecodeError> for ProtoBufPayloadError {
fn from(err: ProtoBufDecodeError) -> ProtoBufPayloadError {
ProtoBufPayloadError::Deserialize(err)
}
}
#[derive(Debug)]
pub struct ProtoBuf<T: Message>(pub T);
impl<T: Message> Responder for ProtoBuf<T> {
type Item = HttpResponse;
type Error = Error;
fn respond_to(self, _: HttpRequest) -> Result<HttpResponse, Error> {
let mut buf = Vec::new();
self.0.encode(&mut buf)
.map_err(|e| Error::from(ProtoBufPayloadError::Serialize(e)))
.and_then(|()| {
Ok(HttpResponse::Ok()
.content_type("application/protobuf")
.body(buf)
.into())
})
}
}
pub struct ProtoBufMessage<T, U: Message + Default>{
limit: usize,
ct: &'static str,
req: Option<T>,
fut: Option<Box<Future<Item=U, Error=ProtoBufPayloadError>>>,
}
impl<T, U: Message + Default> ProtoBufMessage<T, U> {
/// Create `ProtoBufMessage` for request.
pub fn new(req: T) -> Self {
ProtoBufMessage{
limit: 262_144,
req: Some(req),
fut: None,
ct: "application/protobuf",
}
}
/// Change max size of payload. By default max size is 256Kb
pub fn limit(mut self, limit: usize) -> Self {
self.limit = limit;
self
}
/// Set allowed content type.
///
/// By default *application/protobuf* content type is used. Set content type
/// to empty string if you want to disable content type check.
pub fn content_type(mut self, ct: &'static str) -> Self {
self.ct = ct;
self
}
}
impl<T, U: Message + Default + 'static> Future for ProtoBufMessage<T, U>
where T: HttpMessage + Stream<Item=Bytes, Error=PayloadError> + 'static
{
type Item = U;
type Error = ProtoBufPayloadError;
fn poll(&mut self) -> Poll<U, ProtoBufPayloadError> {
if let Some(req) = self.req.take() {
if let Some(len) = req.headers().get(CONTENT_LENGTH) {
if let Ok(s) = len.to_str() {
if let Ok(len) = s.parse::<usize>() {
if len > self.limit {
return Err(ProtoBufPayloadError::Overflow);
}
} else {
return Err(ProtoBufPayloadError::Overflow);
}
}
}
// check content-type
if !self.ct.is_empty() && req.content_type() != self.ct {
return Err(ProtoBufPayloadError::ContentType)
}
let limit = self.limit;
let fut = req.from_err()
.fold(BytesMut::new(), move |mut body, chunk| {
if (body.len() + chunk.len()) > limit {
Err(ProtoBufPayloadError::Overflow)
} else {
body.extend_from_slice(&chunk);
Ok(body)
}
})
.and_then(|body| Ok(<U>::decode(&mut body.into_buf())?));
self.fut = Some(Box::new(fut));
}
self.fut.as_mut().expect("ProtoBufBody could not be used second time").poll()
}
}
pub trait ProtoBufResponseBuilder {
fn protobuf<T: Message>(&mut self, value: T) -> Result<HttpResponse, Error>;
}
impl ProtoBufResponseBuilder for HttpResponseBuilder {
fn protobuf<T: Message>(&mut self, value: T) -> Result<HttpResponse, Error> {
self.header(CONTENT_TYPE, "application/protobuf");
let mut body = Vec::new();
value.encode(&mut body).map_err(|e| ProtoBufPayloadError::Serialize(e))?;
Ok(self.body(body))
}
}

View File

@ -0,0 +1,6 @@
syntax = "proto3";
message MyObj {
int32 number = 1;
string name = 2;
}

View File

@ -0,0 +1,76 @@
# Generated by the protocol buffer compiler. DO NOT EDIT!
# source: test.proto
import sys
_b=sys.version_info[0]<3 and (lambda x:x) or (lambda x:x.encode('latin1'))
from google.protobuf import descriptor as _descriptor
from google.protobuf import message as _message
from google.protobuf import reflection as _reflection
from google.protobuf import symbol_database as _symbol_database
from google.protobuf import descriptor_pb2
# @@protoc_insertion_point(imports)
_sym_db = _symbol_database.Default()
DESCRIPTOR = _descriptor.FileDescriptor(
name='test.proto',
package='',
syntax='proto3',
serialized_pb=_b('\n\ntest.proto\"%\n\x05MyObj\x12\x0e\n\x06number\x18\x01 \x01(\x05\x12\x0c\n\x04name\x18\x02 \x01(\tb\x06proto3')
)
_sym_db.RegisterFileDescriptor(DESCRIPTOR)
_MYOBJ = _descriptor.Descriptor(
name='MyObj',
full_name='MyObj',
filename=None,
file=DESCRIPTOR,
containing_type=None,
fields=[
_descriptor.FieldDescriptor(
name='number', full_name='MyObj.number', index=0,
number=1, type=5, cpp_type=1, label=1,
has_default_value=False, default_value=0,
message_type=None, enum_type=None, containing_type=None,
is_extension=False, extension_scope=None,
options=None),
_descriptor.FieldDescriptor(
name='name', full_name='MyObj.name', index=1,
number=2, type=9, cpp_type=9, label=1,
has_default_value=False, default_value=_b("").decode('utf-8'),
message_type=None, enum_type=None, containing_type=None,
is_extension=False, extension_scope=None,
options=None),
],
extensions=[
],
nested_types=[],
enum_types=[
],
options=None,
is_extendable=False,
syntax='proto3',
extension_ranges=[],
oneofs=[
],
serialized_start=14,
serialized_end=51,
)
DESCRIPTOR.message_types_by_name['MyObj'] = _MYOBJ
MyObj = _reflection.GeneratedProtocolMessageType('MyObj', (_message.Message,), dict(
DESCRIPTOR = _MYOBJ,
__module__ = 'test_pb2'
# @@protoc_insertion_point(class_scope:MyObj)
))
_sym_db.RegisterMessage(MyObj)
# @@protoc_insertion_point(module_scope)

20
examples/r2d2/Cargo.toml Normal file
View File

@ -0,0 +1,20 @@
[package]
name = "r2d2-example"
version = "0.1.0"
authors = ["Nikolay Kim <fafhrd91@gmail.com>"]
workspace = "../.."
[dependencies]
env_logger = "0.5"
actix = "0.5"
actix-web = { path = "../../" }
futures = "0.1"
uuid = { version = "0.5", features = ["serde", "v4"] }
serde = "1.0"
serde_json = "1.0"
serde_derive = "1.0"
r2d2 = "*"
r2d2_sqlite = "*"
rusqlite = "*"

41
examples/r2d2/src/db.rs Normal file
View File

@ -0,0 +1,41 @@
//! Db executor actor
use std::io;
use uuid;
use actix_web::*;
use actix::prelude::*;
use r2d2::Pool;
use r2d2_sqlite::SqliteConnectionManager;
/// This is db executor actor. We are going to run 3 of them in parallel.
pub struct DbExecutor(pub Pool<SqliteConnectionManager>);
/// This is only message that this actor can handle, but it is easy to extend number of
/// messages.
pub struct CreateUser {
pub name: String,
}
impl Message for CreateUser {
type Result = Result<String, io::Error>;
}
impl Actor for DbExecutor {
type Context = SyncContext<Self>;
}
impl Handler<CreateUser> for DbExecutor {
type Result = Result<String, io::Error>;
fn handle(&mut self, msg: CreateUser, _: &mut Self::Context) -> Self::Result {
let conn = self.0.get().unwrap();
let uuid = format!("{}", uuid::Uuid::new_v4());
conn.execute("INSERT INTO users (id, name) VALUES ($1, $2)",
&[&uuid, &msg.name]).unwrap();
Ok(conn.query_row("SELECT name FROM users WHERE id=$1", &[&uuid], |row| {
row.get(0)
}).map_err(|_| io::Error::new(io::ErrorKind::Other, "db error"))?)
}
}

65
examples/r2d2/src/main.rs Normal file
View File

@ -0,0 +1,65 @@
//! Actix web r2d2 example
extern crate serde;
extern crate serde_json;
extern crate uuid;
extern crate futures;
extern crate actix;
extern crate actix_web;
extern crate env_logger;
extern crate r2d2;
extern crate r2d2_sqlite;
extern crate rusqlite;
use actix::prelude::*;
use actix_web::{
middleware, http, server, App, AsyncResponder, HttpRequest, HttpResponse, Error};
use futures::future::Future;
use r2d2_sqlite::SqliteConnectionManager;
mod db;
use db::{CreateUser, DbExecutor};
/// State with DbExecutor address
struct State {
db: Addr<Syn, DbExecutor>,
}
/// Async request handler
fn index(req: HttpRequest<State>) -> Box<Future<Item=HttpResponse, Error=Error>> {
let name = &req.match_info()["name"];
req.state().db.send(CreateUser{name: name.to_owned()})
.from_err()
.and_then(|res| {
match res {
Ok(user) => Ok(HttpResponse::Ok().json(user)),
Err(_) => Ok(HttpResponse::InternalServerError().into())
}
})
.responder()
}
fn main() {
::std::env::set_var("RUST_LOG", "actix_web=debug");
env_logger::init();
let sys = actix::System::new("r2d2-example");
// r2d2 pool
let manager = SqliteConnectionManager::file("test.db");
let pool = r2d2::Pool::new(manager).unwrap();
// Start db executor actors
let addr = SyncArbiter::start(3, move || DbExecutor(pool.clone()));
// Start http server
server::new(move || {
App::with_state(State{db: addr.clone()})
// enable logger
.middleware(middleware::Logger::default())
.resource("/{name}", |r| r.method(http::Method::GET).a(index))})
.bind("127.0.0.1:8080").unwrap()
.start();
let _ = sys.run();
}

BIN
examples/r2d2/test.db Normal file

Binary file not shown.

View File

@ -0,0 +1,11 @@
[package]
name = "redis-session"
version = "0.1.0"
authors = ["Nikolay Kim <fafhrd91@gmail.com>"]
workspace = "../.."
[dependencies]
env_logger = "0.5"
actix = "0.5"
actix-web = "0.5"
actix-redis = { version = "0.3", features = ["web"] }

View File

@ -0,0 +1,48 @@
#![allow(unused_variables)]
extern crate actix;
extern crate actix_web;
extern crate actix_redis;
extern crate env_logger;
use actix_web::{server, App, HttpRequest, HttpResponse, Result};
use actix_web::middleware::{Logger, SessionStorage, RequestSession};
use actix_redis::RedisSessionBackend;
/// simple handler
fn index(mut req: HttpRequest) -> Result<HttpResponse> {
println!("{:?}", req);
// session
if let Some(count) = req.session().get::<i32>("counter")? {
println!("SESSION value: {}", count);
req.session().set("counter", count+1)?;
} else {
req.session().set("counter", 1)?;
}
Ok("Welcome!".into())
}
fn main() {
::std::env::set_var("RUST_LOG", "actix_web=info,actix_redis=info");
env_logger::init();
let sys = actix::System::new("basic-example");
server::new(
|| App::new()
// enable logger
.middleware(Logger::default())
// cookie session middleware
.middleware(SessionStorage::new(
RedisSessionBackend::new("127.0.0.1:6379", &[0; 32])
))
// register simple route, handle all methods
.resource("/", |r| r.f(index)))
.bind("0.0.0.0:8080").unwrap()
.threads(1)
.start();
let _ = sys.run();
}

View File

@ -1,86 +0,0 @@
//! There are two level of statfulness in actix-web. Application has state
//! that is shared across all handlers within same Application.
//! And individual handler can have state.
extern crate actix;
extern crate actix_web;
extern crate env_logger;
use actix::*;
use actix_web::*;
use std::cell::Cell;
struct AppState {
counter: Cell<usize>,
}
/// somple handle
fn index(req: &mut HttpRequest, _: Payload, state: &AppState) -> HttpResponse {
println!("{:?}", req);
state.counter.set(state.counter.get() + 1);
httpcodes::HTTPOk.with_body(
format!("Num of requests: {}", state.counter.get()))
}
/// `MyWebSocket` counts how many messages it receives from peer,
/// websocket-client.py could be used for tests
struct MyWebSocket {
counter: usize,
}
impl Actor for MyWebSocket {
type Context = HttpContext<Self>;
}
impl Route for MyWebSocket {
/// Shared application state
type State = AppState;
fn request(req: &mut HttpRequest,
payload: Payload, ctx: &mut HttpContext<Self>) -> RouteResult<Self>
{
let resp = ws::handshake(req)?;
ctx.start(resp);
ctx.add_stream(ws::WsStream::new(payload));
Reply::async(MyWebSocket{counter: 0})
}
}
impl StreamHandler<ws::Message> for MyWebSocket {}
impl Handler<ws::Message> for MyWebSocket {
fn handle(&mut self, msg: ws::Message, ctx: &mut HttpContext<Self>)
-> Response<Self, ws::Message>
{
self.counter += 1;
println!("WS({}): {:?}", self.counter, msg);
match msg {
ws::Message::Ping(msg) => ws::WsWriter::pong(ctx, &msg),
ws::Message::Text(text) => ws::WsWriter::text(ctx, &text),
ws::Message::Binary(bin) => ws::WsWriter::binary(ctx, bin),
ws::Message::Closed | ws::Message::Error => {
ctx.stop();
}
_ => (),
}
Self::empty()
}
}
fn main() {
::std::env::set_var("RUST_LOG", "actix_web=info");
let _ = env_logger::init();
let sys = actix::System::new("ws-example");
HttpServer::new(
Application::builder("/", AppState{counter: Cell::new(0)})
// enable logger
.middleware(Logger::new(None))
// websocket route
.resource("/ws/", |r| r.get::<MyWebSocket>())
// register simple handler, handle all methods
.handler("/", index))
.serve::<_, ()>("127.0.0.1:8080").unwrap();
println!("Started http server: 127.0.0.1:8080");
let _ = sys.run();
}

11
examples/state/Cargo.toml Normal file
View File

@ -0,0 +1,11 @@
[package]
name = "state"
version = "0.1.0"
authors = ["Nikolay Kim <fafhrd91@gmail.com>"]
workspace = "../.."
[dependencies]
futures = "0.1"
env_logger = "0.5"
actix = "0.5"
actix-web = { path = "../../" }

15
examples/state/README.md Normal file
View File

@ -0,0 +1,15 @@
# state
## Usage
### server
```bash
cd actix-web/examples/state
cargo run
# Started http server: 127.0.0.1:8080
```
### web client
- [http://localhost:8080/](http://localhost:8080/)

View File

@ -0,0 +1,77 @@
#![cfg_attr(feature="cargo-clippy", allow(needless_pass_by_value))]
//! There are two level of statefulness in actix-web. Application has state
//! that is shared across all handlers within same Application.
//! And individual handler can have state.
extern crate actix;
extern crate actix_web;
extern crate env_logger;
use std::cell::Cell;
use actix::prelude::*;
use actix_web::{
http, server, ws, middleware, App, HttpRequest, HttpResponse};
/// Application state
struct AppState {
counter: Cell<usize>,
}
/// simple handle
fn index(req: HttpRequest<AppState>) -> HttpResponse {
println!("{:?}", req);
req.state().counter.set(req.state().counter.get() + 1);
HttpResponse::Ok().body(format!("Num of requests: {}", req.state().counter.get()))
}
/// `MyWebSocket` counts how many messages it receives from peer,
/// websocket-client.py could be used for tests
struct MyWebSocket {
counter: usize,
}
impl Actor for MyWebSocket {
type Context = ws::WebsocketContext<Self, AppState>;
}
impl StreamHandler<ws::Message, ws::ProtocolError> for MyWebSocket {
fn handle(&mut self, msg: ws::Message, ctx: &mut Self::Context) {
self.counter += 1;
println!("WS({}): {:?}", self.counter, msg);
match msg {
ws::Message::Ping(msg) => ctx.pong(&msg),
ws::Message::Text(text) => ctx.text(text),
ws::Message::Binary(bin) => ctx.binary(bin),
ws::Message::Close(_) => {
ctx.stop();
}
_ => (),
}
}
}
fn main() {
::std::env::set_var("RUST_LOG", "actix_web=info");
env_logger::init();
let sys = actix::System::new("ws-example");
server::new(
|| App::with_state(AppState{counter: Cell::new(0)})
// enable logger
.middleware(middleware::Logger::default())
// websocket route
.resource(
"/ws/", |r|
r.method(http::Method::GET).f(
|req| ws::start(req, MyWebSocket{counter: 0})))
// register simple handler, handle all methods
.resource("/", |r| r.f(index)))
.bind("127.0.0.1:8080").unwrap()
.start();
println!("Started http server: 127.0.0.1:8080");
let _ = sys.run();
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 13 KiB

BIN
examples/static/favicon.ico Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB

View File

@ -0,0 +1,11 @@
[package]
name = "template-tera"
version = "0.1.0"
authors = ["Nikolay Kim <fafhrd91@gmail.com>"]
workspace = "../.."
[dependencies]
env_logger = "0.5"
actix = "0.5"
actix-web = { path = "../../" }
tera = "*"

View File

@ -0,0 +1,17 @@
# template_tera
Minimal example of using the template [tera](https://github.com/Keats/tera) that displays a form.
## Usage
### server
```bash
cd actix-web/examples/template_tera
cargo run (or ``cargo watch -x run``)
# Started http server: 127.0.0.1:8080
```
### web client
- [http://localhost:8080](http://localhost:8080)

View File

@ -0,0 +1,48 @@
extern crate actix;
extern crate actix_web;
extern crate env_logger;
#[macro_use]
extern crate tera;
use actix_web::{
http, error, middleware, server, App, HttpRequest, HttpResponse, Error};
struct State {
template: tera::Tera, // <- store tera template in application state
}
fn index(req: HttpRequest<State>) -> Result<HttpResponse, Error> {
let s = if let Some(name) = req.query().get("name") { // <- submitted form
let mut ctx = tera::Context::new();
ctx.add("name", &name.to_owned());
ctx.add("text", &"Welcome!".to_owned());
req.state().template.render("user.html", &ctx)
.map_err(|_| error::ErrorInternalServerError("Template error"))?
} else {
req.state().template.render("index.html", &tera::Context::new())
.map_err(|_| error::ErrorInternalServerError("Template error"))?
};
Ok(HttpResponse::Ok()
.content_type("text/html")
.body(s))
}
fn main() {
::std::env::set_var("RUST_LOG", "actix_web=info");
env_logger::init();
let sys = actix::System::new("tera-example");
server::new(|| {
let tera = compile_templates!(concat!(env!("CARGO_MANIFEST_DIR"), "/templates/**/*"));
App::with_state(State{template: tera})
// enable logger
.middleware(middleware::Logger::default())
.resource("/", |r| r.method(http::Method::GET).f(index))})
.bind("127.0.0.1:8080").unwrap()
.start();
println!("Started http server: 127.0.0.1:8080");
let _ = sys.run();
}

View File

@ -0,0 +1,17 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<title>Actix web</title>
</head>
<body>
<h1>Welcome!</h1>
<p>
<h3>What is your name?</h3>
<form>
<input type="text" name="name" /><br/>
<p><input type="submit"></p>
</form>
</p>
</body>
</html>

View File

@ -0,0 +1,13 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<title>Actix web</title>
</head>
<body>
<h1>Hi, {{ name }}!</h1>
<p>
{{ text }}
</p>
</body>
</html>

15
examples/tls/Cargo.toml Normal file
View File

@ -0,0 +1,15 @@
[package]
name = "tls-example"
version = "0.1.0"
authors = ["Nikolay Kim <fafhrd91@gmail.com>"]
workspace = "../.."
[[bin]]
name = "server"
path = "src/main.rs"
[dependencies]
env_logger = "0.5"
actix = "0.5"
actix-web = { path = "../../", features=["alpn"] }
openssl = { version="0.10" }

16
examples/tls/README.md Normal file
View File

@ -0,0 +1,16 @@
# tls example
## Usage
### server
```bash
cd actix-web/examples/tls
cargo run (or ``cargo watch -x run``)
# Started http server: 127.0.0.1:8443
```
### web client
- curl: ``curl -v https://127.0.0.1:8443/index.html --compress -k``
- browser: [https://127.0.0.1:8443/index.html](https://127.0.0.1:8080/index.html)

31
examples/tls/cert.pem Normal file
View File

@ -0,0 +1,31 @@
-----BEGIN CERTIFICATE-----
MIIFPjCCAyYCCQDvLYiYD+jqeTANBgkqhkiG9w0BAQsFADBhMQswCQYDVQQGEwJV
UzELMAkGA1UECAwCQ0ExCzAJBgNVBAcMAlNGMRAwDgYDVQQKDAdDb21wYW55MQww
CgYDVQQLDANPcmcxGDAWBgNVBAMMD3d3dy5leGFtcGxlLmNvbTAeFw0xODAxMjUx
NzQ2MDFaFw0xOTAxMjUxNzQ2MDFaMGExCzAJBgNVBAYTAlVTMQswCQYDVQQIDAJD
QTELMAkGA1UEBwwCU0YxEDAOBgNVBAoMB0NvbXBhbnkxDDAKBgNVBAsMA09yZzEY
MBYGA1UEAwwPd3d3LmV4YW1wbGUuY29tMIICIjANBgkqhkiG9w0BAQEFAAOCAg8A
MIICCgKCAgEA2WzIA2IpVR9Tb9EFhITlxuhE5rY2a3S6qzYNzQVgSFggxXEPn8k1
sQEcer5BfAP986Sck3H0FvB4Bt/I8PwOtUCmhwcc8KtB5TcGPR4fjXnrpC+MIK5U
NLkwuyBDKziYzTdBj8kUFX1WxmvEHEgqToPOZfBgsS71cJAR/zOWraDLSRM54jXy
voLZN4Ti9rQagQrvTQ44Vz5ycDQy7UxtbUGh1CVv69vNVr7/SOOh/Nw5FNOZWLWr
odGyoec5wh9iqRZgRqiTUc6Lt7V2RWc2X2gjwST2UfI+U46Ip3oaQ7ZD4eAkoqND
xdniBZAykVG3c/99ux4BAESTF8fsNch6UticBxYMuTu+ouvP0psfI9wwwNliJDmA
CRUTB9AgRynbL1AzhqQoDfsb98IZfjfNOpwnwuLwpMAPhbgd5KNdZaIJ4Hb6/stI
yFElOExxd3TAxF2Gshd/lq1JcNHAZ1DSXV5MvOWT/NWgXwbIzUgQ8eIi+HuDYX2U
UuaB6R8tbd52H7rbUv6HrfinuSlKWqjSYLkiKHkwUpoMw8y9UycRSzs1E9nPwPTO
vRXb0mNCQeBCV9FvStNVXdCUTT8LGPv87xSD2pmt7LijlE6mHLG8McfcWkzA69un
CEHIFAFDimTuN7EBljc119xWFTcHMyoZAfFF+oTqwSbBGImruCxnaJECAwEAATAN
BgkqhkiG9w0BAQsFAAOCAgEApavsgsn7SpPHfhDSN5iZs1ILZQRewJg0Bty0xPfk
3tynSW6bNH3nSaKbpsdmxxomthNSQgD2heOq1By9YzeOoNR+7Pk3s4FkASnf3ToI
JNTUasBFFfaCG96s4Yvs8KiWS/k84yaWuU8c3Wb1jXs5Rv1qE1Uvuwat1DSGXSoD
JNluuIkCsC4kWkyq5pWCGQrabWPRTWsHwC3PTcwSRBaFgYLJaR72SloHB1ot02zL
d2age9dmFRFLLCBzP+D7RojBvL37qS/HR+rQ4SoQwiVc/JzaeqSe7ZbvEH9sZYEu
ALowJzgbwro7oZflwTWunSeSGDSltkqKjvWvZI61pwfHKDahUTmZ5h2y67FuGEaC
CIOUI8dSVSPKITxaq3JL4ze2e9/0Lt7hj19YK2uUmtMAW5Tirz4Yx5lyGH9U8Wur
y/X8VPxTc4A9TMlJgkyz0hqvhbPOT/zSWB10zXh0glKAsSBryAOEDxV1UygmSir7
YV8Qaq+oyKUTMc1MFq5vZ07M51EPaietn85t8V2Y+k/8XYltRp32NxsypxAJuyxh
g/ko6RVTrWa1sMvz/F9LFqAdKiK5eM96lh9IU4xiLg4ob8aS/GRAA8oIFkZFhLrt
tOwjIUPmEPyHWFi8dLpNuQKYalLYhuwZftG/9xV+wqhKGZO9iPrpHSYBRTap8w2y
1QU=
-----END CERTIFICATE-----

51
examples/tls/key.pem Normal file
View File

@ -0,0 +1,51 @@
-----BEGIN RSA PRIVATE KEY-----
MIIJKAIBAAKCAgEA2WzIA2IpVR9Tb9EFhITlxuhE5rY2a3S6qzYNzQVgSFggxXEP
n8k1sQEcer5BfAP986Sck3H0FvB4Bt/I8PwOtUCmhwcc8KtB5TcGPR4fjXnrpC+M
IK5UNLkwuyBDKziYzTdBj8kUFX1WxmvEHEgqToPOZfBgsS71cJAR/zOWraDLSRM5
4jXyvoLZN4Ti9rQagQrvTQ44Vz5ycDQy7UxtbUGh1CVv69vNVr7/SOOh/Nw5FNOZ
WLWrodGyoec5wh9iqRZgRqiTUc6Lt7V2RWc2X2gjwST2UfI+U46Ip3oaQ7ZD4eAk
oqNDxdniBZAykVG3c/99ux4BAESTF8fsNch6UticBxYMuTu+ouvP0psfI9wwwNli
JDmACRUTB9AgRynbL1AzhqQoDfsb98IZfjfNOpwnwuLwpMAPhbgd5KNdZaIJ4Hb6
/stIyFElOExxd3TAxF2Gshd/lq1JcNHAZ1DSXV5MvOWT/NWgXwbIzUgQ8eIi+HuD
YX2UUuaB6R8tbd52H7rbUv6HrfinuSlKWqjSYLkiKHkwUpoMw8y9UycRSzs1E9nP
wPTOvRXb0mNCQeBCV9FvStNVXdCUTT8LGPv87xSD2pmt7LijlE6mHLG8McfcWkzA
69unCEHIFAFDimTuN7EBljc119xWFTcHMyoZAfFF+oTqwSbBGImruCxnaJECAwEA
AQKCAgAME3aoeXNCPxMrSri7u4Xnnk71YXl0Tm9vwvjRQlMusXZggP8VKN/KjP0/
9AE/GhmoxqPLrLCZ9ZE1EIjgmZ9Xgde9+C8rTtfCG2RFUL7/5J2p6NonlocmxoJm
YkxYwjP6ce86RTjQWL3RF3s09u0inz9/efJk5O7M6bOWMQ9VZXDlBiRY5BYvbqUR
6FeSzD4MnMbdyMRoVBeXE88gTvZk8xhB6DJnLzYgc0tKiRoeKT0iYv5JZw25VyRM
ycLzfTrFmXCPfB1ylb483d9Ly4fBlM8nkx37PzEnAuukIawDxsPOb9yZC+hfvNJI
7NFiMN+3maEqG2iC00w4Lep4skHY7eHUEUMl+Wjr+koAy2YGLWAwHZQTm7iXn9Ab
L6adL53zyCKelRuEQOzbeosJAqS+5fpMK0ekXyoFIuskj7bWuIoCX7K/kg6q5IW+
vC2FrlsrbQ79GztWLVmHFO1I4J9M5r666YS0qdh8c+2yyRl4FmSiHfGxb3eOKpxQ
b6uI97iZlkxPF9LYUCSc7wq0V2gGz+6LnGvTHlHrOfVXqw/5pLAKhXqxvnroDTwz
0Ay/xFF6ei/NSxBY5t8ztGCBm45wCU3l8pW0X6dXqwUipw5b4MRy1VFRu6rqlmbL
OPSCuLxqyqsigiEYsBgS/icvXz9DWmCQMPd2XM9YhsHvUq+R4QKCAQEA98EuMMXI
6UKIt1kK2t/3OeJRyDd4iv/fCMUAnuPjLBvFE4cXD/SbqCxcQYqb+pue3PYkiTIC
71rN8OQAc5yKhzmmnCE5N26br/0pG4pwEjIr6mt8kZHmemOCNEzvhhT83nfKmV0g
9lNtuGEQMiwmZrpUOF51JOMC39bzcVjYX2Cmvb7cFbIq3lR0zwM+aZpQ4P8LHCIu
bgHmwbdlkLyIULJcQmHIbo6nPFB3ZZE4mqmjwY+rA6Fh9rgBa8OFCfTtrgeYXrNb
IgZQ5U8GoYRPNC2ot0vpTinraboa/cgm6oG4M7FW1POCJTl+/ktHEnKuO5oroSga
/BSg7hCNFVaOhwKCAQEA4Kkys0HtwEbV5mY/NnvUD5KwfXX7BxoXc9lZ6seVoLEc
KjgPYxqYRVrC7dB2YDwwp3qcRTi/uBAgFNm3iYlDzI4xS5SeaudUWjglj7BSgXE2
iOEa7EwcvVPluLaTgiWjlzUKeUCNNHWSeQOt+paBOT+IgwRVemGVpAgkqQzNh/nP
tl3p9aNtgzEm1qVlPclY/XUCtf3bcOR+z1f1b4jBdn0leu5OhnxkC+Htik+2fTXD
jt6JGrMkanN25YzsjnD3Sn+v6SO26H99wnYx5oMSdmb8SlWRrKtfJHnihphjG/YY
l1cyorV6M/asSgXNQfGJm4OuJi0I4/FL2wLUHnU+JwKCAQEAzh4WipcRthYXXcoj
gMKRkMOb3GFh1OpYqJgVExtudNTJmZxq8GhFU51MR27Eo7LycMwKy2UjEfTOnplh
Us2qZiPtW7k8O8S2m6yXlYUQBeNdq9IuuYDTaYD94vsazscJNSAeGodjE+uGvb1q
1wLqE87yoE7dUInYa1cOA3+xy2/CaNuviBFJHtzOrSb6tqqenQEyQf6h9/12+DTW
t5pSIiixHrzxHiFqOoCLRKGToQB+71rSINwTf0nITNpGBWmSj5VcC3VV3TG5/XxI
fPlxV2yhD5WFDPVNGBGvwPDSh4jSMZdZMSNBZCy4XWFNSKjGEWoK4DFYed3DoSt9
5IG1YwKCAQA63ntHl64KJUWlkwNbboU583FF3uWBjee5VqoGKHhf3CkKMxhtGqnt
+oN7t5VdUEhbinhqdx1dyPPvIsHCS3K1pkjqii4cyzNCVNYa2dQ00Qq+QWZBpwwc
3GAkz8rFXsGIPMDa1vxpU6mnBjzPniKMcsZ9tmQDppCEpBGfLpio2eAA5IkK8eEf
cIDB3CM0Vo94EvI76CJZabaE9IJ+0HIJb2+jz9BJ00yQBIqvJIYoNy9gP5Xjpi+T
qV/tdMkD5jwWjHD3AYHLWKUGkNwwkAYFeqT/gX6jpWBP+ZRPOp011X3KInJFSpKU
DT5GQ1Dux7EMTCwVGtXqjO8Ym5wjwwsfAoIBAEcxlhIW1G6BiNfnWbNPWBdh3v/K
5Ln98Rcrz8UIbWyl7qNPjYb13C1KmifVG1Rym9vWMO3KuG5atK3Mz2yLVRtmWAVc
fxzR57zz9MZFDun66xo+Z1wN3fVxQB4CYpOEI4Lb9ioX4v85hm3D6RpFukNtRQEc
Gfr4scTjJX4jFWDp0h6ffMb8mY+quvZoJ0TJqV9L9Yj6Ksdvqez/bdSraev97bHQ
4gbQxaTZ6WjaD4HjpPQefMdWp97Metg0ZQSS8b8EzmNFgyJ3XcjirzwliKTAQtn6
I2sd0NCIooelrKRD8EJoDUwxoOctY7R97wpZ7/wEHU45cBCbRV3H4JILS5c=
-----END RSA PRIVATE KEY-----

49
examples/tls/src/main.rs Normal file
View File

@ -0,0 +1,49 @@
#![allow(unused_variables)]
extern crate actix;
extern crate actix_web;
extern crate env_logger;
extern crate openssl;
use openssl::ssl::{SslMethod, SslAcceptor, SslFiletype};
use actix_web::{
http, middleware, server, App, HttpRequest, HttpResponse, Error};
/// simple handle
fn index(req: HttpRequest) -> Result<HttpResponse, Error> {
println!("{:?}", req);
Ok(HttpResponse::Ok()
.content_type("text/plain")
.body("Welcome!"))
}
fn main() {
if ::std::env::var("RUST_LOG").is_err() {
::std::env::set_var("RUST_LOG", "actix_web=info");
}
env_logger::init();
let sys = actix::System::new("ws-example");
// load ssl keys
let mut builder = SslAcceptor::mozilla_intermediate(SslMethod::tls()).unwrap();
builder.set_private_key_file("key.pem", SslFiletype::PEM).unwrap();
builder.set_certificate_chain_file("cert.pem").unwrap();
server::new(
|| App::new()
// enable logger
.middleware(middleware::Logger::default())
// register simple handler, handle all methods
.resource("/index.html", |r| r.f(index))
// with path parameters
.resource("/", |r| r.method(http::Method::GET).f(|req| {
HttpResponse::Found()
.header("LOCATION", "/index.html")
.finish()
})))
.bind("127.0.0.1:8443").unwrap()
.start_ssl(builder).unwrap();
println!("Started http server: 127.0.0.1:8443");
let _ = sys.run();
}

View File

@ -0,0 +1,10 @@
[package]
name = "unix-socket"
version = "0.1.0"
authors = ["Messense Lv <messense@icloud.com>"]
[dependencies]
env_logger = "0.5"
actix = "0.5"
actix-web = { path = "../../" }
tokio-uds = "0.1"

View File

@ -0,0 +1,14 @@
## Unix domain socket example
```bash
$ curl --unix-socket /tmp/actix-uds.socket http://localhost/
Hello world!
```
Although this will only one thread for handling incoming connections
according to the
[documentation](https://actix.github.io/actix-web/actix_web/struct.HttpServer.html#method.start_incoming).
And it does not delete the socket file (`/tmp/actix-uds.socket`) when stopping
the server so it will fail to start next time you run it unless you delete
the socket file manually.

View File

@ -0,0 +1,32 @@
extern crate actix;
extern crate actix_web;
extern crate env_logger;
extern crate tokio_uds;
use actix::*;
use actix_web::{middleware, server, App, HttpRequest};
use tokio_uds::UnixListener;
fn index(_req: HttpRequest) -> &'static str {
"Hello world!"
}
fn main() {
::std::env::set_var("RUST_LOG", "actix_web=info");
env_logger::init();
let sys = actix::System::new("unix-socket");
let listener = UnixListener::bind(
"/tmp/actix-uds.socket", Arbiter::handle()).expect("bind failed");
server::new(
|| App::new()
// enable logger
.middleware(middleware::Logger::default())
.resource("/index.html", |r| r.f(|_| "Hello world!"))
.resource("/", |r| r.f(index)))
.start_incoming(listener.incoming(), false);
println!("Started http server: /tmp/actix-uds.socket");
let _ = sys.run();
}

View File

@ -0,0 +1,15 @@
# Actix Web CORS example
## start
1 - backend server
```bash
$ cd web-cors/backend
$ cargo run
```
2 - frontend server
```bash
$ cd web-cors/frontend
$ npm install
$ npm run dev
```
then open browser 'http://localhost:1234/'

4
examples/web-cors/backend/.gitignore vendored Normal file
View File

@ -0,0 +1,4 @@
/target/
**/*.rs.bk
Cargo.lock

View File

@ -0,0 +1,17 @@
[package]
name = "actix-web-cors"
version = "0.1.0"
authors = ["krircc <krircc@aliyun.com>"]
workspace = "../../../"
[dependencies]
serde = "1.0"
serde_derive = "1.0"
serde_json = "1.0"
http = "0.1"
actix = "0.5"
actix-web = { path = "../../../" }
dotenv = "0.10"
env_logger = "0.5"
futures = "0.1"

View File

@ -0,0 +1,43 @@
#[macro_use] extern crate serde_derive;
extern crate serde;
extern crate serde_json;
extern crate futures;
extern crate actix;
extern crate actix_web;
extern crate env_logger;
use std::env;
use actix_web::{http, middleware, server, App};
mod user;
use user::info;
fn main() {
env::set_var("RUST_LOG", "actix_web=info");
env_logger::init();
let sys = actix::System::new("Actix-web-CORS");
server::new(
|| App::new()
.middleware(middleware::Logger::default())
.resource("/user/info", |r| {
middleware::cors::Cors::build()
.allowed_origin("http://localhost:1234")
.allowed_methods(vec!["GET", "POST"])
.allowed_headers(
vec![http::header::AUTHORIZATION,
http::header::ACCEPT,
http::header::CONTENT_TYPE])
.max_age(3600)
.finish().expect("Can not create CORS middleware")
.register(r);
r.method(http::Method::POST).a(info);
}))
.bind("127.0.0.1:8000").unwrap()
.shutdown_timeout(200)
.start();
let _ = sys.run();
}

View File

@ -0,0 +1,19 @@
use actix_web::{AsyncResponder, Error, HttpMessage, HttpResponse, HttpRequest};
use futures::Future;
#[derive(Deserialize,Serialize, Debug)]
struct Info {
username: String,
email: String,
password: String,
confirm_password: String,
}
pub fn info(req: HttpRequest) -> Box<Future<Item=HttpResponse, Error=Error>> {
req.json()
.from_err()
.and_then(|res: Info| {
Ok(HttpResponse::Ok().json(res))
}).responder()
}

View File

@ -0,0 +1,3 @@
{
"presets": ["env"]
}

14
examples/web-cors/frontend/.gitignore vendored Normal file
View File

@ -0,0 +1,14 @@
.DS_Store
node_modules/
/dist/
.cache
npm-debug.log*
yarn-debug.log*
yarn-error.log*
# Editor directories and files
.idea
*.suo
*.ntvs*
*.njsproj
*.sln

View File

@ -0,0 +1,13 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width,initial-scale=1.0">
<title>webapp</title>
</head>
<body>
<div id="app"></div>
<script src="./src/main.js"></script>
</body>
</html>

View File

@ -0,0 +1,22 @@
{
"name": "actix-web-cors",
"version": "0.1.0",
"description": "webapp",
"main": "main.js",
"scripts": {
"dev": "rm -rf dist/ && NODE_ENV=development parcel index.html",
"build": "NODE_ENV=production parcel build index.html",
"test": "echo \"Error: no test specified\" && exit 1"
},
"license": "ISC",
"dependencies": {
"vue": "^2.5.13",
"vue-router": "^3.0.1",
"axios": "^0.17.1"
},
"devDependencies": {
"babel-preset-env": "^1.6.1",
"parcel-bundler": "^1.4.1",
"parcel-plugin-vue": "^1.5.0"
}
}

View File

@ -0,0 +1,145 @@
<template>
<div id="app">
<div id="content">
<div id="title">
<a to="#">SignUp</a>
</div>
<input type="text" name="username" placeholder="Username" v-model="Username" required />
<input type="text" name="email" placeholder="E-mail" v-model="Email" required />
<input type="password" name="password" placeholder="Password" v-model="Password" required/>
<input type="password" name="confirm_password" placeholder="Confirm password" v-model="ConfirmPassword" required/><br/>
<button id="submit" @click="signup">Sign up</button>
<div id="user-info">
<p>Click Above 'Sign up' Button <br> Then Get Your Signup Info!</p>
<p>email : {{ email }}</p>
<p>username {{ username }}</p>
<p>password : {{ password }}</p>
</div>
</div>
</div>
</template>
<script>
import axios from 'axios'
export default {
name: 'app',
data () {
return {
Username: '',
Email: '',
Password: '',
ConfirmPassword: '',
email: '',
username: '',
password: ''
}
},
methods: {
signup () {
var username = this.Username
var email = this.Email
var password = this.Password
var confirm_password = this.ConfirmPassword
console.log(email)
axios.post('http://localhost:8000/user/info', {
username: username,
email: email,
password: password,
confirm_password: confirm_password
})
.then(response => {
console.log(response.data)
this.email = response.data.email
this.username = response.data.username
this.password = response.data.password
})
.catch(e => {
console.log(e)
})
}
}
}
</script>
<style scoped>
#content {
width: 250px;
margin: 0 auto;
padding-top: 33px;
}
#title {
padding: 0.5rem 0;
font-size: 22px;
font-weight: bold;
background-color:bisque;
text-align: center;
}
input[type="text"],
input[type="password"] {
margin: 6px auto auto;
width: 250px;
height: 36px;
border: none;
border-bottom: 1px solid #AAA;
font-size: 16px;
}
#submit {
margin: 10px 0 20px 0;
width: 250px;
height: 33px;
background-color:bisque;
border: none;
border-radius: 2px;
font-family: 'Roboto', sans-serif;
font-weight: bold;
text-transform: uppercase;
transition: 0.1s ease;
cursor: pointer;
}
input[type="checkbox"] {
margin-top: 11px;
}
dialog {
top: 50%;
width: 80%;
border: 5px solid rgba(0, 0, 0, 0.3);
}
dialog::backdrop{
position: fixed;
top: 0;
left: 0;
right: 0;
bottom: 0;
background-color: rgba(0, 0, 0, 0.7);
}
#closeDialog {
display: inline-block;
border-radius: 3px;
border: none;
font-size: 1rem;
padding: 0.4rem 0.8em;
background: #eb9816;
border-bottom: 1px solid #f1b75c;
color: white;
font-weight: bold;
text-align: center;
}
#closeDialog:hover, #closeDialog:focus {
opacity: 0.92;
cursor: pointer;
}
#user-info {
width: 250px;
margin: 0 auto;
padding-top: 44px;
}
@media only screen and (min-width: 600px) {
#content {
margin: 0 auto;
padding-top: 100px;
}
}
</style>

View File

@ -0,0 +1,11 @@
import Vue from 'vue'
import App from './app'
new Vue({
el: '#app',
render: h => h(App)
})
if (module.hot) {
module.hot.accept();
}

View File

@ -2,6 +2,7 @@
name = "websocket-example" name = "websocket-example"
version = "0.1.0" version = "0.1.0"
authors = ["Nikolay Kim <fafhrd91@gmail.com>"] authors = ["Nikolay Kim <fafhrd91@gmail.com>"]
workspace = "../.."
[[bin]] [[bin]]
name = "server" name = "server"
@ -24,6 +25,5 @@ serde = "1.0"
serde_json = "1.0" serde_json = "1.0"
serde_derive = "1.0" serde_derive = "1.0"
#actix = "0.3" actix = "0.5"
actix = { git = "https://github.com/actix/actix.git" } actix-web = { path="../../" }
actix-web = { path = "../../" }

View File

@ -9,17 +9,15 @@ Added features:
* Chat server runs in separate thread * Chat server runs in separate thread
* Tcp listener runs in separate thread * Tcp listener runs in separate thread
## Server ## Server
Chat server listens for incoming tcp connections. Server can access several types of message: Chat server listens for incoming tcp connections. Server can access several types of message:
* `\list` - list all available rooms * `\list` - list all available rooms
* `\join name` - join room, if room does not exist, create new one * `\join name` - join room, if room does not exist, create new one
* `\name name` - set session name * `\name name` - set session name
* `some message` - just string, send messsage to all peers in same room * `some message` - just string, send message to all peers in same room
* client has to send heartbeat `Ping` messages, if server does not receive a heartbeat * client has to send heartbeat `Ping` messages, if server does not receive a heartbeat message for 10 seconds connection gets dropped
message for 10 seconds connection gets droppped
To start server use command: `cargo run --bin server` To start server use command: `cargo run --bin server`
@ -29,7 +27,6 @@ Client connects to server. Reads input from stdin and sends to server.
To run client use command: `cargo run --bin client` To run client use command: `cargo run --bin client`
## WebSocket Browser Client ## WebSocket Browser Client
Open url: http://localhost:8080/ Open url: [http://localhost:8080/](http://localhost:8080/)

View File

@ -1,4 +1,4 @@
extern crate actix; #[macro_use] extern crate actix;
extern crate bytes; extern crate bytes;
extern crate byteorder; extern crate byteorder;
extern crate futures; extern crate futures;
@ -12,6 +12,9 @@ use std::{io, net, process, thread};
use std::str::FromStr; use std::str::FromStr;
use std::time::Duration; use std::time::Duration;
use futures::Future; use futures::Future;
use tokio_io::AsyncRead;
use tokio_io::io::WriteHalf;
use tokio_io::codec::FramedRead;
use tokio_core::net::TcpStream; use tokio_core::net::TcpStream;
use actix::prelude::*; use actix::prelude::*;
@ -26,7 +29,12 @@ fn main() {
Arbiter::handle().spawn( Arbiter::handle().spawn(
TcpStream::connect(&addr, Arbiter::handle()) TcpStream::connect(&addr, Arbiter::handle())
.and_then(|stream| { .and_then(|stream| {
let addr: SyncAddress<_> = ChatClient.framed(stream, codec::ClientChatCodec); let addr: Addr<Syn, _> = ChatClient::create(|ctx| {
let (r, w) = stream.split();
ChatClient::add_stream(FramedRead::new(r, codec::ClientChatCodec), ctx);
ChatClient{
framed: actix::io::FramedWrite::new(
w, codec::ClientChatCodec, ctx)}});
// start console loop // start console loop
thread::spawn(move|| { thread::spawn(move|| {
@ -37,7 +45,7 @@ fn main() {
return return
} }
addr.send(ClientCommand(cmd)); addr.do_send(ClientCommand(cmd));
} }
}); });
@ -54,43 +62,48 @@ fn main() {
} }
struct ChatClient; struct ChatClient {
framed: actix::io::FramedWrite<WriteHalf<TcpStream>, codec::ClientChatCodec>,
struct ClientCommand(String);
impl ResponseType for ClientCommand {
type Item = ();
type Error = ();
} }
impl Actor for ChatClient { #[derive(Message)]
type Context = FramedContext<Self>; struct ClientCommand(String);
fn started(&mut self, ctx: &mut FramedContext<Self>) { impl Actor for ChatClient {
type Context = Context<Self>;
fn started(&mut self, ctx: &mut Context<Self>) {
// start heartbeats otherwise server will disconnect after 10 seconds // start heartbeats otherwise server will disconnect after 10 seconds
self.hb(ctx) self.hb(ctx)
} }
fn stopped(&mut self, _: &mut Context<Self>) {
println!("Disconnected");
// Stop application on disconnect
Arbiter::system().do_send(actix::msgs::SystemExit(0));
}
} }
impl ChatClient { impl ChatClient {
fn hb(&self, ctx: &mut FramedContext<Self>) { fn hb(&self, ctx: &mut Context<Self>) {
ctx.run_later(Duration::new(1, 0), |act, ctx| { ctx.run_later(Duration::new(1, 0), |act, ctx| {
if ctx.send(codec::ChatRequest::Ping).is_ok() { act.framed.write(codec::ChatRequest::Ping);
act.hb(ctx); act.hb(ctx);
}
}); });
} }
} }
impl actix::io::WriteHandler<io::Error> for ChatClient {}
/// Handle stdin commands /// Handle stdin commands
impl Handler<ClientCommand> for ChatClient impl Handler<ClientCommand> for ChatClient {
{ type Result = ();
fn handle(&mut self, msg: ClientCommand, ctx: &mut FramedContext<Self>)
-> Response<Self, ClientCommand> fn handle(&mut self, msg: ClientCommand, _: &mut Context<Self>) {
{
let m = msg.0.trim(); let m = msg.0.trim();
if m.is_empty() { if m.is_empty() {
return Self::empty() return
} }
// we check for /sss type of messages // we check for /sss type of messages
@ -98,11 +111,11 @@ impl Handler<ClientCommand> for ChatClient
let v: Vec<&str> = m.splitn(2, ' ').collect(); let v: Vec<&str> = m.splitn(2, ' ').collect();
match v[0] { match v[0] {
"/list" => { "/list" => {
let _ = ctx.send(codec::ChatRequest::List); self.framed.write(codec::ChatRequest::List);
}, },
"/join" => { "/join" => {
if v.len() == 2 { if v.len() == 2 {
let _ = ctx.send(codec::ChatRequest::Join(v[1].to_owned())); self.framed.write(codec::ChatRequest::Join(v[1].to_owned()));
} else { } else {
println!("!!! room name is required"); println!("!!! room name is required");
} }
@ -110,35 +123,16 @@ impl Handler<ClientCommand> for ChatClient
_ => println!("!!! unknown command"), _ => println!("!!! unknown command"),
} }
} else { } else {
let _ = ctx.send(codec::ChatRequest::Message(m.to_owned())); self.framed.write(codec::ChatRequest::Message(m.to_owned()));
} }
Self::empty()
} }
} }
/// Server communication /// Server communication
impl FramedActor for ChatClient {
type Io = TcpStream;
type Codec = codec::ClientChatCodec;
}
impl StreamHandler<codec::ChatResponse, io::Error> for ChatClient { impl StreamHandler<codec::ChatResponse, io::Error> for ChatClient {
fn finished(&mut self, _: &mut FramedContext<Self>) { fn handle(&mut self, msg: codec::ChatResponse, _: &mut Context<Self>) {
println!("Disconnected");
// Stop application on disconnect
Arbiter::system().send(msgs::SystemExit(0));
}
}
impl Handler<codec::ChatResponse, io::Error> for ChatClient {
fn handle(&mut self, msg: codec::ChatResponse, _: &mut FramedContext<Self>)
-> Response<Self, codec::ChatResponse>
{
match msg { match msg {
codec::ChatResponse::Message(ref msg) => { codec::ChatResponse::Message(ref msg) => {
println!("message: {}", msg); println!("message: {}", msg);
@ -155,7 +149,5 @@ impl Handler<codec::ChatResponse, io::Error> for ChatClient {
} }
_ => (), _ => (),
} }
Self::empty()
} }
} }

View File

@ -4,10 +4,9 @@ use serde_json as json;
use byteorder::{BigEndian , ByteOrder}; use byteorder::{BigEndian , ByteOrder};
use bytes::{BytesMut, BufMut}; use bytes::{BytesMut, BufMut};
use tokio_io::codec::{Encoder, Decoder}; use tokio_io::codec::{Encoder, Decoder};
use actix::ResponseType;
/// Client request /// Client request
#[derive(Serialize, Deserialize, Debug)] #[derive(Serialize, Deserialize, Debug, Message)]
#[serde(tag="cmd", content="data")] #[serde(tag="cmd", content="data")]
pub enum ChatRequest { pub enum ChatRequest {
/// List rooms /// List rooms
@ -20,13 +19,8 @@ pub enum ChatRequest {
Ping Ping
} }
impl ResponseType for ChatRequest {
type Item = ();
type Error = ();
}
/// Server response /// Server response
#[derive(Serialize, Deserialize, Debug)] #[derive(Serialize, Deserialize, Debug, Message)]
#[serde(tag="cmd", content="data")] #[serde(tag="cmd", content="data")]
pub enum ChatResponse { pub enum ChatResponse {
Ping, Ping,
@ -41,11 +35,6 @@ pub enum ChatResponse {
Message(String), Message(String),
} }
impl ResponseType for ChatResponse {
type Item = ();
type Error = ();
}
/// Codec for Client -> Server transport /// Codec for Client -> Server transport
pub struct ChatCodec; pub struct ChatCodec;

View File

@ -10,23 +10,35 @@ extern crate serde;
extern crate serde_json; extern crate serde_json;
#[macro_use] extern crate serde_derive; #[macro_use] extern crate serde_derive;
#[macro_use]
extern crate actix; extern crate actix;
extern crate actix_web; extern crate actix_web;
use std::time::Instant; use std::time::Instant;
use actix::*; use actix::*;
use actix_web::*; use actix_web::server::HttpServer;
use actix_web::{http, fs, ws, App, HttpRequest, HttpResponse, Error};
mod codec; mod codec;
mod server; mod server;
mod session; mod session;
/// This is our websocket route state, this state is shared with all route instances /// This is our websocket route state, this state is shared with all route instances
/// via `HttpContext::state()` /// via `HttpContext::state()`
struct WsChatSessionState { struct WsChatSessionState {
addr: SyncAddress<server::ChatServer>, addr: Addr<Syn, server::ChatServer>,
}
/// Entry point for our route
fn chat_route(req: HttpRequest<WsChatSessionState>) -> Result<HttpResponse, Error> {
ws::start(
req,
WsChatSession {
id: 0,
hb: Instant::now(),
room: "Main".to_owned(),
name: None})
} }
struct WsChatSession { struct WsChatSession {
@ -41,50 +53,53 @@ struct WsChatSession {
} }
impl Actor for WsChatSession { impl Actor for WsChatSession {
type Context = HttpContext<Self>; type Context = ws::WebsocketContext<Self, WsChatSessionState>;
}
/// Entry point for our route /// Method is called on actor start.
impl Route for WsChatSession { /// We register ws session with ChatServer
type State = WsChatSessionState; fn started(&mut self, ctx: &mut Self::Context) {
// register self in chat server. `AsyncContext::wait` register
// future within context, but context waits until this future resolves
// before processing any other events.
// HttpContext::state() is instance of WsChatSessionState, state is shared across all
// routes within application
let addr: Addr<Syn, _> = ctx.address();
ctx.state().addr.send(server::Connect{addr: addr.recipient()})
.into_actor(self)
.then(|res, act, ctx| {
match res {
Ok(res) => act.id = res,
// something is wrong with chat server
_ => ctx.stop(),
}
fut::ok(())
}).wait(ctx);
}
fn request(req: &mut HttpRequest, fn stopping(&mut self, ctx: &mut Self::Context) -> Running {
payload: Payload, ctx: &mut HttpContext<Self>) -> RouteResult<Self> // notify chat server
{ ctx.state().addr.do_send(server::Disconnect{id: self.id});
// websocket handshakre, it may fail if request is not websocket request Running::Stop
let resp = ws::handshake(&req)?;
ctx.start(resp);
ctx.add_stream(ws::WsStream::new(payload));
Reply::async(
WsChatSession {
id: 0,
hb: Instant::now(),
room: "Main".to_owned(),
name: None})
} }
} }
/// Handle messages from chat server, we simply send it to peer websocket /// Handle messages from chat server, we simply send it to peer websocket
impl Handler<session::Message> for WsChatSession { impl Handler<session::Message> for WsChatSession {
fn handle(&mut self, msg: session::Message, ctx: &mut HttpContext<Self>) type Result = ();
-> Response<Self, session::Message>
{ fn handle(&mut self, msg: session::Message, ctx: &mut Self::Context) {
ws::WsWriter::text(ctx, &msg.0); ctx.text(msg.0);
Self::empty()
} }
} }
/// WebSocket message handler /// WebSocket message handler
impl Handler<ws::Message> for WsChatSession { impl StreamHandler<ws::Message, ws::ProtocolError> for WsChatSession {
fn handle(&mut self, msg: ws::Message, ctx: &mut HttpContext<Self>)
-> Response<Self, ws::Message> fn handle(&mut self, msg: ws::Message, ctx: &mut Self::Context) {
{
println!("WEBSOCKET MESSAGE: {:?}", msg); println!("WEBSOCKET MESSAGE: {:?}", msg);
match msg { match msg {
ws::Message::Ping(msg) => ws::Message::Ping(msg) => ctx.pong(&msg),
ws::WsWriter::pong(ctx, &msg), ws::Message::Pong(msg) => self.hb = Instant::now(),
ws::Message::Pong(msg) =>
self.hb = Instant::now(),
ws::Message::Text(text) => { ws::Message::Text(text) => {
let m = text.trim(); let m = text.trim();
// we check for /sss type of messages // we check for /sss type of messages
@ -94,17 +109,19 @@ impl Handler<ws::Message> for WsChatSession {
"/list" => { "/list" => {
// Send ListRooms message to chat server and wait for response // Send ListRooms message to chat server and wait for response
println!("List rooms"); println!("List rooms");
ctx.state().addr.call(self, server::ListRooms).then(|res, _, ctx| { ctx.state().addr.send(server::ListRooms)
match res { .into_actor(self)
Ok(Ok(rooms)) => { .then(|res, _, ctx| {
for room in rooms { match res {
ws::WsWriter::text(ctx, &room); Ok(rooms) => {
} for room in rooms {
}, ctx.text(room);
_ => println!("Something is wrong"), }
} },
fut::ok(()) _ => println!("Something is wrong"),
}).wait(ctx) }
fut::ok(())
}).wait(ctx)
// .wait(ctx) pauses all events in context, // .wait(ctx) pauses all events in context,
// so actor wont receive any new messages until it get list // so actor wont receive any new messages until it get list
// of rooms back // of rooms back
@ -112,23 +129,22 @@ impl Handler<ws::Message> for WsChatSession {
"/join" => { "/join" => {
if v.len() == 2 { if v.len() == 2 {
self.room = v[1].to_owned(); self.room = v[1].to_owned();
ctx.state().addr.send( ctx.state().addr.do_send(
server::Join{id: self.id, name: self.room.clone()}); server::Join{id: self.id, name: self.room.clone()});
ws::WsWriter::text(ctx, "joined"); ctx.text("joined");
} else { } else {
ws::WsWriter::text(ctx, "!!! room name is required"); ctx.text("!!! room name is required");
} }
}, },
"/name" => { "/name" => {
if v.len() == 2 { if v.len() == 2 {
self.name = Some(v[1].to_owned()); self.name = Some(v[1].to_owned());
} else { } else {
ws::WsWriter::text(ctx, "!!! name is required"); ctx.text("!!! name is required");
} }
}, },
_ => ws::WsWriter::text( _ => ctx.text(format!("!!! unknown command: {:?}", m)),
ctx, &format!("!!! unknown command: {:?}", m)),
} }
} else { } else {
let msg = if let Some(ref name) = self.name { let msg = if let Some(ref name) = self.name {
@ -137,7 +153,7 @@ impl Handler<ws::Message> for WsChatSession {
m.to_owned() m.to_owned()
}; };
// send message to chat server // send message to chat server
ctx.state().addr.send( ctx.state().addr.do_send(
server::Message{id: self.id, server::Message{id: self.id,
msg: msg, msg: msg,
room: self.room.clone()}) room: self.room.clone()})
@ -145,82 +161,49 @@ impl Handler<ws::Message> for WsChatSession {
}, },
ws::Message::Binary(bin) => ws::Message::Binary(bin) =>
println!("Unexpected binary"), println!("Unexpected binary"),
ws::Message::Closed | ws::Message::Error => { ws::Message::Close(_) => {
ctx.stop(); ctx.stop();
} }
_ => (),
} }
Self::empty()
} }
} }
impl StreamHandler<ws::Message> for WsChatSession
{
/// Method is called when stream get polled first time.
/// We register ws session with ChatServer
fn started(&mut self, ctx: &mut Self::Context) {
// register self in chat server. `AsyncContext::wait` register
// future within context, but context waits until this future resolves
// before processing any other events.
// HttpContext::state() is instance of WsChatSessionState, state is shared across all
// routes within application
let subs = ctx.sync_subscriber();
ctx.state().addr.call(
self, server::Connect{addr: subs}).then(
|res, act, ctx| {
match res {
Ok(Ok(res)) => act.id = res,
// something is wrong with chat server
_ => ctx.stop(),
}
fut::ok(())
}).wait(ctx);
}
/// Method is called when stream finishes, even if stream finishes with error.
fn finished(&mut self, ctx: &mut Self::Context) {
// notify chat server
ctx.state().addr.send(server::Disconnect{id: self.id});
ctx.stop()
}
}
fn main() { fn main() {
let _ = env_logger::init(); let _ = env_logger::init();
let sys = actix::System::new("websocket-example"); let sys = actix::System::new("websocket-example");
// Start chat server actor in separate thread // Start chat server actor in separate thread
let server: SyncAddress<_> = let server: Addr<Syn, _> = Arbiter::start(|_| server::ChatServer::default());
Arbiter::start(|_| server::ChatServer::default());
// Start tcp server in separate thread // Start tcp server in separate thread
let srv = server.clone(); let srv = server.clone();
Arbiter::new("tcp-server").send::<msgs::Execute>( Arbiter::new("tcp-server").do_send::<msgs::Execute>(
msgs::Execute::new(move || { msgs::Execute::new(move || {
session::TcpServer::new("127.0.0.1:12345", srv); session::TcpServer::new("127.0.0.1:12345", srv);
Ok(()) Ok(())
})); }));
// Websocket sessions state
let state = WsChatSessionState { addr: server };
// Create Http server with websocket support // Create Http server with websocket support
HttpServer::new( HttpServer::new(
Application::builder("/", state) move || {
// redirect to websocket.html // Websocket sessions state
.resource("/", |r| let state = WsChatSessionState { addr: server.clone() };
r.handler(Method::GET, |req, payload, state| {
Ok(httpcodes::HTTPFound
.builder()
.header("LOCATION", "/static/websocket.html")
.body(Body::Empty)?)
}))
// websocket
.resource("/ws/", |r| r.get::<WsChatSession>())
// static resources
.route_handler("/static", StaticFiles::new("static/", true)))
.serve::<_, ()>("127.0.0.1:8080").unwrap();
App::with_state(state)
// redirect to websocket.html
.resource("/", |r| r.method(http::Method::GET).f(|_| {
HttpResponse::Found()
.header("LOCATION", "/static/websocket.html")
.finish()
}))
// websocket
.resource("/ws/", |r| r.route().f(chat_route))
// static resources
.handler("/static/", fs::StaticFiles::new("static/"))
})
.bind("127.0.0.1:8080").unwrap()
.start();
println!("Started http server: 127.0.0.1:8080");
let _ = sys.run(); let _ = sys.run();
} }

View File

@ -12,29 +12,20 @@ use session;
/// Message for chat server communications /// Message for chat server communications
/// New chat session is created /// New chat session is created
#[derive(Message)]
#[rtype(usize)]
pub struct Connect { pub struct Connect {
pub addr: Box<Subscriber<session::Message> + Send>, pub addr: Recipient<Syn, session::Message>,
}
/// Response type for Connect message
///
/// Chat server returns unique session id
impl ResponseType for Connect {
type Item = usize;
type Error = ();
} }
/// Session is disconnected /// Session is disconnected
#[derive(Message)]
pub struct Disconnect { pub struct Disconnect {
pub id: usize, pub id: usize,
} }
impl ResponseType for Disconnect {
type Item = ();
type Error = ();
}
/// Send message to specific room /// Send message to specific room
#[derive(Message)]
pub struct Message { pub struct Message {
/// Id of the client session /// Id of the client session
pub id: usize, pub id: usize,
@ -44,20 +35,15 @@ pub struct Message {
pub room: String, pub room: String,
} }
impl ResponseType for Message {
type Item = ();
type Error = ();
}
/// List of available rooms /// List of available rooms
pub struct ListRooms; pub struct ListRooms;
impl ResponseType for ListRooms { impl actix::Message for ListRooms {
type Item = Vec<String>; type Result = Vec<String>;
type Error = ();
} }
/// Join room, if room does not exists create new one. /// Join room, if room does not exists create new one.
#[derive(Message)]
pub struct Join { pub struct Join {
/// Client id /// Client id
pub id: usize, pub id: usize,
@ -65,15 +51,10 @@ pub struct Join {
pub name: String, pub name: String,
} }
impl ResponseType for Join {
type Item = ();
type Error = ();
}
/// `ChatServer` manages chat rooms and responsible for coordinating chat session. /// `ChatServer` manages chat rooms and responsible for coordinating chat session.
/// implementation is super primitive /// implementation is super primitive
pub struct ChatServer { pub struct ChatServer {
sessions: HashMap<usize, Box<Subscriber<session::Message> + Send>>, sessions: HashMap<usize, Recipient<Syn, session::Message>>,
rooms: HashMap<String, HashSet<usize>>, rooms: HashMap<String, HashSet<usize>>,
rng: RefCell<ThreadRng>, rng: RefCell<ThreadRng>,
} }
@ -99,7 +80,7 @@ impl ChatServer {
for id in sessions { for id in sessions {
if *id != skip_id { if *id != skip_id {
if let Some(addr) = self.sessions.get(id) { if let Some(addr) = self.sessions.get(id) {
let _ = addr.send(session::Message(message.to_owned())); let _ = addr.do_send(session::Message(message.to_owned()));
} }
} }
} }
@ -118,8 +99,9 @@ impl Actor for ChatServer {
/// ///
/// Register new session and assign unique id to this session /// Register new session and assign unique id to this session
impl Handler<Connect> for ChatServer { impl Handler<Connect> for ChatServer {
type Result = usize;
fn handle(&mut self, msg: Connect, _: &mut Context<Self>) -> Response<Self, Connect> { fn handle(&mut self, msg: Connect, _: &mut Context<Self>) -> Self::Result {
println!("Someone joined"); println!("Someone joined");
// notify all users in same room // notify all users in same room
@ -133,14 +115,15 @@ impl Handler<Connect> for ChatServer {
self.rooms.get_mut(&"Main".to_owned()).unwrap().insert(id); self.rooms.get_mut(&"Main".to_owned()).unwrap().insert(id);
// send id back // send id back
Self::reply(id) id
} }
} }
/// Handler for Disconnect message. /// Handler for Disconnect message.
impl Handler<Disconnect> for ChatServer { impl Handler<Disconnect> for ChatServer {
type Result = ();
fn handle(&mut self, msg: Disconnect, _: &mut Context<Self>) -> Response<Self, Disconnect> { fn handle(&mut self, msg: Disconnect, _: &mut Context<Self>) {
println!("Someone disconnected"); println!("Someone disconnected");
let mut rooms: Vec<String> = Vec::new(); let mut rooms: Vec<String> = Vec::new();
@ -158,40 +141,39 @@ impl Handler<Disconnect> for ChatServer {
for room in rooms { for room in rooms {
self.send_message(&room, "Someone disconnected", 0); self.send_message(&room, "Someone disconnected", 0);
} }
Self::empty()
} }
} }
/// Handler for Message message. /// Handler for Message message.
impl Handler<Message> for ChatServer { impl Handler<Message> for ChatServer {
type Result = ();
fn handle(&mut self, msg: Message, _: &mut Context<Self>) -> Response<Self, Message> { fn handle(&mut self, msg: Message, _: &mut Context<Self>) {
self.send_message(&msg.room, msg.msg.as_str(), msg.id); self.send_message(&msg.room, msg.msg.as_str(), msg.id);
Self::empty()
} }
} }
/// Handler for `ListRooms` message. /// Handler for `ListRooms` message.
impl Handler<ListRooms> for ChatServer { impl Handler<ListRooms> for ChatServer {
type Result = MessageResult<ListRooms>;
fn handle(&mut self, _: ListRooms, _: &mut Context<Self>) -> Response<Self, ListRooms> { fn handle(&mut self, _: ListRooms, _: &mut Context<Self>) -> Self::Result {
let mut rooms = Vec::new(); let mut rooms = Vec::new();
for key in self.rooms.keys() { for key in self.rooms.keys() {
rooms.push(key.to_owned()) rooms.push(key.to_owned())
} }
Self::reply(rooms) MessageResult(rooms)
} }
} }
/// Join room, send disconnect message to old room /// Join room, send disconnect message to old room
/// send join message to new room /// send join message to new room
impl Handler<Join> for ChatServer { impl Handler<Join> for ChatServer {
type Result = ();
fn handle(&mut self, msg: Join, _: &mut Context<Self>) -> Response<Self, Join> { fn handle(&mut self, msg: Join, _: &mut Context<Self>) {
let Join {id, name} = msg; let Join {id, name} = msg;
let mut rooms = Vec::new(); let mut rooms = Vec::new();
@ -211,7 +193,5 @@ impl Handler<Join> for ChatServer {
} }
self.send_message(&name, "Someone connected", id); self.send_message(&name, "Someone connected", id);
self.rooms.get_mut(&name).unwrap().insert(id); self.rooms.get_mut(&name).unwrap().insert(id);
Self::empty()
} }
} }

View File

@ -4,113 +4,102 @@ use std::{io, net};
use std::str::FromStr; use std::str::FromStr;
use std::time::{Instant, Duration}; use std::time::{Instant, Duration};
use futures::Stream; use futures::Stream;
use tokio_io::AsyncRead;
use tokio_io::io::WriteHalf;
use tokio_io::codec::FramedRead;
use tokio_core::net::{TcpStream, TcpListener}; use tokio_core::net::{TcpStream, TcpListener};
use actix::*; use actix::prelude::*;
use server::{self, ChatServer}; use server::{self, ChatServer};
use codec::{ChatRequest, ChatResponse, ChatCodec}; use codec::{ChatRequest, ChatResponse, ChatCodec};
/// Chat server sends this messages to session /// Chat server sends this messages to session
#[derive(Message)]
pub struct Message(pub String); pub struct Message(pub String);
impl ResponseType for Message { /// `ChatSession` actor is responsible for tcp peer communications.
type Item = ();
type Error = ();
}
/// `ChatSession` actor is responsible for tcp peer communitions.
pub struct ChatSession { pub struct ChatSession {
/// unique session id /// unique session id
id: usize, id: usize,
/// this is address of chat server /// this is address of chat server
addr: SyncAddress<ChatServer>, addr: Addr<Syn, ChatServer>,
/// Client must send ping at least once per 10 seconds, otherwise we drop connection. /// Client must send ping at least once per 10 seconds, otherwise we drop connection.
hb: Instant, hb: Instant,
/// joined room /// joined room
room: String, room: String,
/// Framed wrapper
framed: actix::io::FramedWrite<WriteHalf<TcpStream>, ChatCodec>,
} }
impl Actor for ChatSession { impl Actor for ChatSession {
/// For tcp communication we are going to use `FramedContext`. /// For tcp communication we are going to use `FramedContext`.
/// It is convinient wrapper around `Framed` object from `tokio_io` /// It is convenient wrapper around `Framed` object from `tokio_io`
type Context = FramedContext<Self>; type Context = Context<Self>;
}
/// To use `FramedContext` we have to define Io type and Codec fn started(&mut self, ctx: &mut Self::Context) {
impl FramedActor for ChatSession {
type Io = TcpStream;
type Codec= ChatCodec;
}
/// Also `FramedContext` requires Actor which is able to handle stream
/// of `<Codec as Decoder>::Item` items.
impl StreamHandler<ChatRequest, io::Error> for ChatSession {
fn started(&mut self, ctx: &mut FramedContext<Self>) {
// we'll start heartbeat process on session start. // we'll start heartbeat process on session start.
self.hb(ctx); self.hb(ctx);
// register self in chat server. `AsyncContext::wait` register // register self in chat server. `AsyncContext::wait` register
// future within context, but context waits until this future resolves // future within context, but context waits until this future resolves
// before processing any other events. // before processing any other events.
self.addr.call(self, server::Connect{addr: ctx.sync_subscriber()}).then(|res, act, ctx| { let addr: Addr<Syn, _> = ctx.address();
match res { self.addr.send(server::Connect{addr: addr.recipient()})
Ok(Ok(res)) => act.id = res, .into_actor(self)
// something is wrong with chat server .then(|res, act, ctx| {
_ => ctx.stop(), match res {
} Ok(res) => act.id = res,
fut::ok(()) // something is wrong with chat server
}).wait(ctx); _ => ctx.stop(),
}
actix::fut::ok(())
}).wait(ctx);
} }
fn finished(&mut self, ctx: &mut FramedContext<Self>) { fn stopping(&mut self, ctx: &mut Self::Context) -> Running {
// notify chat server // notify chat server
self.addr.send(server::Disconnect{id: self.id}); self.addr.do_send(server::Disconnect{id: self.id});
Running::Stop
ctx.stop()
} }
} }
impl Handler<ChatRequest, io::Error> for ChatSession { impl actix::io::WriteHandler<io::Error> for ChatSession {}
/// We'll stop chat session actor on any error, high likely it is just /// To use `Framed` we have to define Io type and Codec
/// termination of the tcp stream. impl StreamHandler<ChatRequest, io::Error> for ChatSession {
fn error(&mut self, _: io::Error, ctx: &mut FramedContext<Self>) {
ctx.stop()
}
/// This is main event loop for client requests /// This is main event loop for client requests
fn handle(&mut self, msg: ChatRequest, ctx: &mut FramedContext<Self>) fn handle(&mut self, msg: ChatRequest, ctx: &mut Context<Self>) {
-> Response<Self, ChatRequest>
{
match msg { match msg {
ChatRequest::List => { ChatRequest::List => {
// Send ListRooms message to chat server and wait for response // Send ListRooms message to chat server and wait for response
println!("List rooms"); println!("List rooms");
self.addr.call(self, server::ListRooms).then(|res, _, ctx| { self.addr.send(server::ListRooms)
match res { .into_actor(self)
Ok(Ok(rooms)) => { .then(|res, act, ctx| {
let _ = ctx.send(ChatResponse::Rooms(rooms)); match res {
}, Ok(rooms) => {
_ => println!("Something is wrong"), act.framed.write(ChatResponse::Rooms(rooms));
} },
fut::ok(()) _ => println!("Something is wrong"),
}).wait(ctx) }
actix::fut::ok(())
}).wait(ctx)
// .wait(ctx) pauses all events in context, // .wait(ctx) pauses all events in context,
// so actor wont receive any new messages until it get list of rooms back // so actor wont receive any new messages until it get list of rooms back
}, },
ChatRequest::Join(name) => { ChatRequest::Join(name) => {
println!("Join to room: {}", name); println!("Join to room: {}", name);
self.room = name.clone(); self.room = name.clone();
self.addr.send(server::Join{id: self.id, name: name.clone()}); self.addr.do_send(server::Join{id: self.id, name: name.clone()});
let _ = ctx.send(ChatResponse::Joined(name)); self.framed.write(ChatResponse::Joined(name));
}, },
ChatRequest::Message(message) => { ChatRequest::Message(message) => {
// send message to chat server // send message to chat server
println!("Peer message: {}", message); println!("Peer message: {}", message);
self.addr.send( self.addr.do_send(
server::Message{id: self.id, server::Message{id: self.id,
msg: message, room: msg: message, room:
self.room.clone()}) self.room.clone()})
@ -119,35 +108,32 @@ impl Handler<ChatRequest, io::Error> for ChatSession {
ChatRequest::Ping => ChatRequest::Ping =>
self.hb = Instant::now(), self.hb = Instant::now(),
} }
Self::empty()
} }
} }
/// Handler for Message, chat server sends this message, we just send string to peer /// Handler for Message, chat server sends this message, we just send string to peer
impl Handler<Message> for ChatSession { impl Handler<Message> for ChatSession {
type Result = ();
fn handle(&mut self, msg: Message, ctx: &mut FramedContext<Self>) fn handle(&mut self, msg: Message, ctx: &mut Context<Self>) {
-> Response<Self, Message>
{
// send message to peer // send message to peer
let _ = ctx.send(ChatResponse::Message(msg.0)); self.framed.write(ChatResponse::Message(msg.0));
Self::empty()
} }
} }
/// Helper methods /// Helper methods
impl ChatSession { impl ChatSession {
pub fn new(addr: SyncAddress<ChatServer>) -> ChatSession { pub fn new(addr: Addr<Syn,ChatServer>,
ChatSession {id: 0, addr: addr, hb: Instant::now(), room: "Main".to_owned()} framed: actix::io::FramedWrite<WriteHalf<TcpStream>, ChatCodec>) -> ChatSession {
ChatSession {id: 0, addr: addr, hb: Instant::now(),
room: "Main".to_owned(), framed: framed}
} }
/// helper method that sends ping to client every second. /// helper method that sends ping to client every second.
/// ///
/// also this method check heartbeats from client /// also this method check heartbeats from client
fn hb(&self, ctx: &mut FramedContext<Self>) { fn hb(&self, ctx: &mut Context<Self>) {
ctx.run_later(Duration::new(1, 0), |act, ctx| { ctx.run_later(Duration::new(1, 0), |act, ctx| {
// check client heartbeats // check client heartbeats
if Instant::now().duration_since(act.hb) > Duration::new(10, 0) { if Instant::now().duration_since(act.hb) > Duration::new(10, 0) {
@ -155,29 +141,28 @@ impl ChatSession {
println!("Client heartbeat failed, disconnecting!"); println!("Client heartbeat failed, disconnecting!");
// notify chat server // notify chat server
act.addr.send(server::Disconnect{id: act.id}); act.addr.do_send(server::Disconnect{id: act.id});
// stop actor // stop actor
ctx.stop(); ctx.stop();
} }
if ctx.send(ChatResponse::Ping).is_ok() { act.framed.write(ChatResponse::Ping);
// if we can not send message to sink, sink is closed (disconnected) // if we can not send message to sink, sink is closed (disconnected)
act.hb(ctx); act.hb(ctx);
}
}); });
} }
} }
/// Define tcp server that will accept incomint tcp connection and create /// Define tcp server that will accept incoming tcp connection and create
/// chat actors. /// chat actors.
pub struct TcpServer { pub struct TcpServer {
chat: SyncAddress<ChatServer>, chat: Addr<Syn, ChatServer>,
} }
impl TcpServer { impl TcpServer {
pub fn new(s: &str, chat: SyncAddress<ChatServer>) { pub fn new(s: &str, chat: Addr<Syn, ChatServer>) {
// Create server listener // Create server listener
let addr = net::SocketAddr::from_str("127.0.0.1:12345").unwrap(); let addr = net::SocketAddr::from_str("127.0.0.1:12345").unwrap();
let listener = TcpListener::bind(&addr, Arbiter::handle()).unwrap(); let listener = TcpListener::bind(&addr, Arbiter::handle()).unwrap();
@ -188,7 +173,9 @@ impl TcpServer {
// So to be able to handle this events `Server` actor has to implement // So to be able to handle this events `Server` actor has to implement
// stream handler `StreamHandler<(TcpStream, net::SocketAddr), io::Error>` // stream handler `StreamHandler<(TcpStream, net::SocketAddr), io::Error>`
let _: () = TcpServer::create(|ctx| { let _: () = TcpServer::create(|ctx| {
ctx.add_stream(listener.incoming().map(|(t, a)| TcpConnect(t, a))); ctx.add_message_stream(listener.incoming()
.map_err(|_| ())
.map(|(t, a)| TcpConnect(t, a)));
TcpServer{chat: chat} TcpServer{chat: chat}
}); });
} }
@ -200,27 +187,21 @@ impl Actor for TcpServer {
type Context = Context<Self>; type Context = Context<Self>;
} }
#[derive(Message)]
struct TcpConnect(TcpStream, net::SocketAddr); struct TcpConnect(TcpStream, net::SocketAddr);
impl ResponseType for TcpConnect {
type Item = ();
type Error = ();
}
/// Handle stream of TcpStream's /// Handle stream of TcpStream's
impl StreamHandler<TcpConnect, io::Error> for TcpServer {} impl Handler<TcpConnect> for TcpServer {
type Result = ();
impl Handler<TcpConnect, io::Error> for TcpServer { fn handle(&mut self, msg: TcpConnect, _: &mut Context<Self>) {
fn handle(&mut self, msg: TcpConnect, _: &mut Context<Self>) -> Response<Self, TcpConnect>
{
// For each incoming connection we create `ChatSession` actor // For each incoming connection we create `ChatSession` actor
// with out chat server address. // with out chat server address.
let server = self.chat.clone(); let server = self.chat.clone();
let _: () = ChatSession::new(server).framed(msg.0, ChatCodec); let _: () = ChatSession::create(|ctx| {
let (r, w) = msg.0.split();
// this is response for message, which is defined by `ResponseType` trait ChatSession::add_stream(FramedRead::new(r, ChatCodec), ctx);
// in this case we just return unit. ChatSession::new(server, actix::io::FramedWrite::new(w, ChatCodec, ctx))
Self::empty() });
} }
} }

View File

@ -1,85 +0,0 @@
//! Simple echo websocket server.
//! Open `http://localhost:8080/ws/index.html` in browser
//! or [python console client](https://github.com/actix/actix-web/blob/master/examples/websocket-client.py)
//! could be used for testing.
#![allow(unused_variables)]
extern crate actix;
extern crate actix_web;
extern crate env_logger;
use actix::*;
use actix_web::*;
struct MyWebSocket;
impl Actor for MyWebSocket {
type Context = HttpContext<Self>;
}
/// Http route handler
impl Route for MyWebSocket {
type State = ();
fn request(req: &mut HttpRequest,
payload: Payload, ctx: &mut HttpContext<Self>) -> RouteResult<Self>
{
// websocket handshake
let resp = ws::handshake(req)?;
// send HttpResponse back to peer
ctx.start(resp);
// convert bytes stream to a stream of `ws::Message` and register it
ctx.add_stream(ws::WsStream::new(payload));
Reply::async(MyWebSocket)
}
}
/// Standard actix's stream handler for a stream of `ws::Message`
impl StreamHandler<ws::Message> for MyWebSocket {
fn started(&mut self, ctx: &mut Self::Context) {
println!("WebSocket session openned");
}
fn finished(&mut self, ctx: &mut Self::Context) {
println!("WebSocket session closed");
}
}
impl Handler<ws::Message> for MyWebSocket {
fn handle(&mut self, msg: ws::Message, ctx: &mut HttpContext<Self>)
-> Response<Self, ws::Message>
{
// process websocket messages
println!("WS: {:?}", msg);
match msg {
ws::Message::Ping(msg) => ws::WsWriter::pong(ctx, &msg),
ws::Message::Text(text) => ws::WsWriter::text(ctx, &text),
ws::Message::Binary(bin) => ws::WsWriter::binary(ctx, bin),
ws::Message::Closed | ws::Message::Error => {
ctx.stop();
}
_ => (),
}
Self::empty()
}
}
fn main() {
::std::env::set_var("RUST_LOG", "actix_web=info");
let _ = env_logger::init();
let sys = actix::System::new("ws-example");
HttpServer::new(
Application::default("/")
// enable logger
.middleware(Logger::new(None))
// websocket route
.resource("/ws/", |r| r.get::<MyWebSocket>())
.route_handler("/", StaticFiles::new("examples/static/", true)))
// start http server on 127.0.0.1:8080
.serve::<_, ()>("127.0.0.1:8080").unwrap();
println!("Started http server: 127.0.0.1:8080");
let _ = sys.run();
}

View File

@ -0,0 +1,20 @@
[package]
name = "websocket"
version = "0.1.0"
authors = ["Nikolay Kim <fafhrd91@gmail.com>"]
workspace = "../.."
[[bin]]
name = "server"
path = "src/main.rs"
[[bin]]
name = "client"
path = "src/client.rs"
[dependencies]
env_logger = "*"
futures = "0.1"
tokio-core = "0.1"
actix = "0.5"
actix-web = { path="../../" }

View File

@ -0,0 +1,27 @@
# websocket
Simple echo websocket server.
## Usage
### server
```bash
cd actix-web/examples/websocket
cargo run
# Started http server: 127.0.0.1:8080
```
### web client
- [http://localhost:8080/ws/index.html](http://localhost:8080/ws/index.html)
### python client
- ``pip install aiohttp``
- ``python websocket-client.py``
if ubuntu :
- ``pip3 install aiohttp``
- ``python3 websocket-client.py``

View File

@ -0,0 +1,113 @@
//! Simple websocket client.
#![allow(unused_variables)]
extern crate actix;
extern crate actix_web;
extern crate env_logger;
extern crate futures;
extern crate tokio_core;
use std::{io, thread};
use std::time::Duration;
use actix::*;
use futures::Future;
use actix_web::ws::{Message, ProtocolError, Client, ClientWriter};
fn main() {
::std::env::set_var("RUST_LOG", "actix_web=info");
let _ = env_logger::init();
let sys = actix::System::new("ws-example");
Arbiter::handle().spawn(
Client::new("http://127.0.0.1:8080/ws/")
.connect()
.map_err(|e| {
println!("Error: {}", e);
()
})
.map(|(reader, writer)| {
let addr: Addr<Syn, _> = ChatClient::create(|ctx| {
ChatClient::add_stream(reader, ctx);
ChatClient(writer)
});
// start console loop
thread::spawn(move|| {
loop {
let mut cmd = String::new();
if io::stdin().read_line(&mut cmd).is_err() {
println!("error");
return
}
addr.do_send(ClientCommand(cmd));
}
});
()
})
);
let _ = sys.run();
}
struct ChatClient(ClientWriter);
#[derive(Message)]
struct ClientCommand(String);
impl Actor for ChatClient {
type Context = Context<Self>;
fn started(&mut self, ctx: &mut Context<Self>) {
// start heartbeats otherwise server will disconnect after 10 seconds
self.hb(ctx)
}
fn stopped(&mut self, _: &mut Context<Self>) {
println!("Disconnected");
// Stop application on disconnect
Arbiter::system().do_send(actix::msgs::SystemExit(0));
}
}
impl ChatClient {
fn hb(&self, ctx: &mut Context<Self>) {
ctx.run_later(Duration::new(1, 0), |act, ctx| {
act.0.ping("");
act.hb(ctx);
});
}
}
/// Handle stdin commands
impl Handler<ClientCommand> for ChatClient {
type Result = ();
fn handle(&mut self, msg: ClientCommand, ctx: &mut Context<Self>) {
self.0.text(msg.0)
}
}
/// Handle server websocket messages
impl StreamHandler<Message, ProtocolError> for ChatClient {
fn handle(&mut self, msg: Message, ctx: &mut Context<Self>) {
match msg {
Message::Text(txt) => println!("Server: {:?}", txt),
_ => ()
}
}
fn started(&mut self, ctx: &mut Context<Self>) {
println!("Connected");
}
fn finished(&mut self, ctx: &mut Context<Self>) {
println!("Server disconnected");
ctx.stop()
}
}

View File

@ -0,0 +1,66 @@
//! Simple echo websocket server.
//! Open `http://localhost:8080/ws/index.html` in browser
//! or [python console client](https://github.com/actix/actix-web/blob/master/examples/websocket-client.py)
//! could be used for testing.
#![allow(unused_variables)]
extern crate actix;
extern crate actix_web;
extern crate env_logger;
use actix::prelude::*;
use actix_web::{
http, middleware, server, fs, ws, App, HttpRequest, HttpResponse, Error};
/// do websocket handshake and start `MyWebSocket` actor
fn ws_index(r: HttpRequest) -> Result<HttpResponse, Error> {
ws::start(r, MyWebSocket)
}
/// websocket connection is long running connection, it easier
/// to handle with an actor
struct MyWebSocket;
impl Actor for MyWebSocket {
type Context = ws::WebsocketContext<Self>;
}
/// Handler for `ws::Message`
impl StreamHandler<ws::Message, ws::ProtocolError> for MyWebSocket {
fn handle(&mut self, msg: ws::Message, ctx: &mut Self::Context) {
// process websocket messages
println!("WS: {:?}", msg);
match msg {
ws::Message::Ping(msg) => ctx.pong(&msg),
ws::Message::Text(text) => ctx.text(text),
ws::Message::Binary(bin) => ctx.binary(bin),
ws::Message::Close(_) => {
ctx.stop();
}
_ => (),
}
}
}
fn main() {
::std::env::set_var("RUST_LOG", "actix_web=info");
env_logger::init();
let sys = actix::System::new("ws-example");
server::new(
|| App::new()
// enable logger
.middleware(middleware::Logger::default())
// websocket route
.resource("/ws/", |r| r.method(http::Method::GET).f(ws_index))
// static files
.handler("/", fs::StaticFiles::new("../static/")
.index_file("index.html")))
// start http server on 127.0.0.1:8080
.bind("127.0.0.1:8080").unwrap()
.start();
println!("Started http server: 127.0.0.1:8080");
let _ = sys.run();
}

Some files were not shown because too many files have changed in this diff Show More