#1754 expose on_connect v2

Open Rob Ede robjtede
Coverage Reach
actix-http/src/h1/dispatcher.rs actix-http/src/h1/decoder.rs actix-http/src/h1/encoder.rs actix-http/src/h1/service.rs actix-http/src/h1/client.rs actix-http/src/h1/codec.rs actix-http/src/h1/payload.rs actix-http/src/h1/utils.rs actix-http/src/h1/mod.rs actix-http/src/h1/expect.rs actix-http/src/h1/upgrade.rs actix-http/src/header/common/content_disposition.rs actix-http/src/header/common/range.rs actix-http/src/header/common/content_range.rs actix-http/src/header/common/cache_control.rs actix-http/src/header/common/if_range.rs actix-http/src/header/common/mod.rs actix-http/src/header/common/content_type.rs actix-http/src/header/common/accept.rs actix-http/src/header/common/date.rs actix-http/src/header/common/last_modified.rs actix-http/src/header/common/allow.rs actix-http/src/header/shared/charset.rs actix-http/src/header/shared/entity.rs actix-http/src/header/shared/quality_item.rs actix-http/src/header/shared/httpdate.rs actix-http/src/header/shared/encoding.rs actix-http/src/header/map.rs actix-http/src/header/mod.rs actix-http/src/client/pool.rs actix-http/src/client/connector.rs actix-http/src/client/h1proto.rs actix-http/src/client/h2proto.rs actix-http/src/client/connection.rs actix-http/src/client/error.rs actix-http/src/client/config.rs actix-http/src/ws/codec.rs actix-http/src/ws/frame.rs actix-http/src/ws/proto.rs actix-http/src/ws/mod.rs actix-http/src/ws/mask.rs actix-http/src/ws/dispatcher.rs actix-http/src/response.rs actix-http/src/h2/dispatcher.rs actix-http/src/h2/service.rs actix-http/src/h2/mod.rs actix-http/src/encoding/encoder.rs actix-http/src/encoding/decoder.rs actix-http/src/encoding/mod.rs actix-http/src/message.rs actix-http/src/service.rs actix-http/src/body.rs actix-http/src/error.rs actix-http/src/config.rs actix-http/src/test.rs actix-http/src/builder.rs actix-http/src/request.rs actix-http/src/httpmessage.rs actix-http/src/helpers.rs actix-http/src/extensions.rs actix-http/src/time_parser.rs actix-http/src/payload.rs actix-http/src/cloneable.rs actix-http/src/httpcodes.rs actix-http/src/macros.rs src/types/json.rs src/types/payload.rs src/types/form.rs src/types/path.rs src/types/readlines.rs src/types/query.rs src/middleware/logger.rs src/middleware/normalize.rs src/middleware/defaultheaders.rs src/middleware/compress.rs src/middleware/errhandlers.rs src/middleware/condition.rs src/scope.rs src/test.rs src/request.rs src/resource.rs src/server.rs src/service.rs src/app.rs src/rmap.rs src/responder.rs src/guard.rs src/app_service.rs src/data.rs src/info.rs src/config.rs src/route.rs src/extract.rs src/request_data.rs src/handler.rs src/error.rs src/web.rs src/lib.rs awc/src/request.rs awc/src/ws.rs awc/src/sender.rs awc/src/response.rs awc/src/frozen.rs awc/src/builder.rs awc/src/connect.rs awc/src/test.rs awc/src/lib.rs awc/src/error.rs actix-files/src/named.rs actix-files/src/files.rs actix-files/src/service.rs actix-files/src/range.rs actix-files/src/chunked.rs actix-files/src/path_buf.rs actix-files/src/directory.rs actix-files/src/error.rs actix-files/src/lib.rs tests/test_server.rs tests/test_httpserver.rs actix-multipart/src/server.rs actix-multipart/src/extractor.rs actix-multipart/src/error.rs actix-web-actors/src/ws.rs actix-web-actors/src/context.rs actix-web-codegen/src/route.rs

No flags found

Use flags to group coverage reports by test type, project and/or folders.
Then setup custom commit statuses and notifications for each flag.

e.g., #unittest #integration

#production #enterprise

#frontend #backend

Learn more about Codecov Flags here.


@@ -24,6 +24,7 @@
Loading
24 24
use crate::payload::Payload;
25 25
use crate::request::Request;
26 26
use crate::response::Response;
27 +
use crate::Extensions;
27 28
28 29
const CHUNK_SIZE: usize = 16_384;
29 30
@@ -36,6 +37,7 @@
Loading
36 37
    service: CloneableService<S>,
37 38
    connection: Connection<T, Bytes>,
38 39
    on_connect: Option<Box<dyn DataFactory>>,
40 +
    on_connect_data: Extensions,
39 41
    config: ServiceConfig,
40 42
    peer_addr: Option<net::SocketAddr>,
41 43
    ka_expire: Instant,
@@ -56,6 +58,7 @@
Loading
56 58
        service: CloneableService<S>,
57 59
        connection: Connection<T, Bytes>,
58 60
        on_connect: Option<Box<dyn DataFactory>>,
61 +
        on_connect_data: Extensions,
59 62
        config: ServiceConfig,
60 63
        timeout: Option<Delay>,
61 64
        peer_addr: Option<net::SocketAddr>,
@@ -82,6 +85,7 @@
Loading
82 85
            peer_addr,
83 86
            connection,
84 87
            on_connect,
88 +
            on_connect_data,
85 89
            ka_expire,
86 90
            ka_timer,
87 91
            _t: PhantomData,
@@ -130,11 +134,15 @@
Loading
130 134
                    head.headers = parts.headers.into();
131 135
                    head.peer_addr = this.peer_addr;
132 136
137 +
                    // DEPRECATED
133 138
                    // set on_connect data
134 139
                    if let Some(ref on_connect) = this.on_connect {
135 140
                        on_connect.set(&mut req.extensions_mut());
136 141
                    }
137 142
143 +
                    // merge on_connect_ext data into request extensions
144 +
                    req.extensions_mut().drain_from(&mut this.on_connect_data);
145 +
138 146
                    actix_rt::spawn(ServiceResponse::<
139 147
                        S::Future,
140 148
                        S::Response,

@@ -1,5 +1,5 @@
Loading
1 1
use std::any::{Any, TypeId};
2 -
use std::fmt;
2 +
use std::{fmt, mem};
3 3
4 4
use fxhash::FxHashMap;
5 5
@@ -66,6 +66,11 @@
Loading
66 66
    pub fn extend(&mut self, other: Extensions) {
67 67
        self.map.extend(other.map);
68 68
    }
69 +
70 +
    /// Sets (or overrides) items from `other` into this map.
71 +
    pub(crate) fn drain_from(&mut self, other: &mut Self) {
72 +
        self.map.extend(mem::take(&mut other.map));
73 +
    }
69 74
}
70 75
71 76
impl fmt::Debug for Extensions {
@@ -213,4 +218,27 @@
Loading
213 218
        assert_eq!(extensions.get(), Some(&20u8));
214 219
        assert_eq!(extensions.get_mut(), Some(&mut 20u8));
215 220
    }
221 +
222 +
    #[test]
223 +
    fn test_drain_from() {
224 +
        let mut ext = Extensions::new();
225 +
        ext.insert(2isize);
226 +
227 +
        let mut more_ext = Extensions::new();
228 +
229 +
        more_ext.insert(5isize);
230 +
        more_ext.insert(5usize);
231 +
232 +
        assert_eq!(ext.get::<isize>(), Some(&2isize));
233 +
        assert_eq!(ext.get::<usize>(), None);
234 +
        assert_eq!(more_ext.get::<isize>(), Some(&5isize));
235 +
        assert_eq!(more_ext.get::<usize>(), Some(&5usize));
236 +
237 +
        ext.drain_from(&mut more_ext);
238 +
239 +
        assert_eq!(ext.get::<isize>(), Some(&5isize));
240 +
        assert_eq!(ext.get::<usize>(), Some(&5usize));
241 +
        assert_eq!(more_ext.get::<isize>(), None);
242 +
        assert_eq!(more_ext.get::<usize>(), None);
243 +
    }
216 244
}

@@ -50,6 +50,7 @@
Loading
50 50
        self.0.extend_from_slice(buf);
51 51
        Ok(buf.len())
52 52
    }
53 +
53 54
    fn flush(&mut self) -> io::Result<()> {
54 55
        Ok(())
55 56
    }

@@ -14,10 +14,11 @@
Loading
14 14
use crate::request::Request;
15 15
use crate::response::Response;
16 16
use crate::service::HttpService;
17 +
use crate::{ConnectCallback, Extensions};
17 18
18 -
/// A http service builder
19 +
/// A HTTP service builder
19 20
///
20 -
/// This type can be used to construct an instance of `http service` through a
21 +
/// This type can be used to construct an instance of [`HttpService`] through a
21 22
/// builder-like pattern.
22 23
pub struct HttpServiceBuilder<T, S, X = ExpectHandler, U = UpgradeHandler<T>> {
23 24
    keep_alive: KeepAlive,
@@ -27,7 +28,9 @@
Loading
27 28
    local_addr: Option<net::SocketAddr>,
28 29
    expect: X,
29 30
    upgrade: Option<U>,
31 +
    // DEPRECATED: in favor of on_connect_ext
30 32
    on_connect: Option<Rc<dyn Fn(&T) -> Box<dyn DataFactory>>>,
33 +
    on_connect_ext: Option<Rc<ConnectCallback<T>>>,
31 34
    _t: PhantomData<(T, S)>,
32 35
}
33 36
@@ -49,6 +52,7 @@
Loading
49 52
            expect: ExpectHandler,
50 53
            upgrade: None,
51 54
            on_connect: None,
55 +
            on_connect_ext: None,
52 56
            _t: PhantomData,
53 57
        }
54 58
    }
@@ -138,6 +142,7 @@
Loading
138 142
            expect: expect.into_factory(),
139 143
            upgrade: self.upgrade,
140 144
            on_connect: self.on_connect,
145 +
            on_connect_ext: self.on_connect_ext,
141 146
            _t: PhantomData,
142 147
        }
143 148
    }
@@ -167,14 +172,16 @@
Loading
167 172
            expect: self.expect,
168 173
            upgrade: Some(upgrade.into_factory()),
169 174
            on_connect: self.on_connect,
175 +
            on_connect_ext: self.on_connect_ext,
170 176
            _t: PhantomData,
171 177
        }
172 178
    }
173 179
174 180
    /// Set on-connect callback.
175 181
    ///
176 -
    /// It get called once per connection and result of the call
177 -
    /// get stored to the request's extensions.
182 +
    /// Called once per connection. Return value of the call is stored in request extensions.
183 +
    ///
184 +
    /// *SOFT DEPRECATED*: Prefer the `on_connect_ext` style callback.
178 185
    pub fn on_connect<F, I>(mut self, f: F) -> Self
179 186
    where
180 187
        F: Fn(&T) -> I + 'static,
@@ -184,7 +191,20 @@
Loading
184 191
        self
185 192
    }
186 193
187 -
    /// Finish service configuration and create *http service* for HTTP/1 protocol.
194 +
    /// Sets the callback to be run on connection establishment.
195 +
    ///
196 +
    /// Has mutable access to a data container that will be merged into request extensions.
197 +
    /// This enables transport layer data (like client certificates) to be accessed in middleware
198 +
    /// and handlers.
199 +
    pub fn on_connect_ext<F>(mut self, f: F) -> Self
200 +
    where
201 +
        F: Fn(&T, &mut Extensions) + 'static,
202 +
    {
203 +
        self.on_connect_ext = Some(Rc::new(f));
204 +
        self
205 +
    }
206 +
207 +
    /// Finish service configuration and create a HTTP Service for HTTP/1 protocol.
188 208
    pub fn h1<F, B>(self, service: F) -> H1Service<T, S, B, X, U>
189 209
    where
190 210
        B: MessageBody,
@@ -200,13 +220,15 @@
Loading
200 220
            self.secure,
201 221
            self.local_addr,
202 222
        );
223 +
203 224
        H1Service::with_config(cfg, service.into_factory())
204 225
            .expect(self.expect)
205 226
            .upgrade(self.upgrade)
206 227
            .on_connect(self.on_connect)
228 +
            .on_connect_ext(self.on_connect_ext)
207 229
    }
208 230
209 -
    /// Finish service configuration and create *http service* for HTTP/2 protocol.
231 +
    /// Finish service configuration and create a HTTP service for HTTP/2 protocol.
210 232
    pub fn h2<F, B>(self, service: F) -> H2Service<T, S, B>
211 233
    where
212 234
        B: MessageBody + 'static,
@@ -223,7 +245,10 @@
Loading
223 245
            self.secure,
224 246
            self.local_addr,
225 247
        );
226 -
        H2Service::with_config(cfg, service.into_factory()).on_connect(self.on_connect)
248 +
249 +
        H2Service::with_config(cfg, service.into_factory())
250 +
            .on_connect(self.on_connect)
251 +
            .on_connect_ext(self.on_connect_ext)
227 252
    }
228 253
229 254
    /// Finish service configuration and create `HttpService` instance.
@@ -243,9 +268,11 @@
Loading
243 268
            self.secure,
244 269
            self.local_addr,
245 270
        );
271 +
246 272
        HttpService::with_config(cfg, service.into_factory())
247 273
            .expect(self.expect)
248 274
            .upgrade(self.upgrade)
249 275
            .on_connect(self.on_connect)
276 +
            .on_connect_ext(self.on_connect_ext)
250 277
    }
251 278
}

@@ -1,7 +1,7 @@
Loading
1 1
use std::marker::PhantomData;
2 2
use std::pin::Pin;
3 3
use std::task::{Context, Poll};
4 -
use std::{fmt, net, rc};
4 +
use std::{fmt, net, rc::Rc};
5 5
6 6
use actix_codec::{AsyncRead, AsyncWrite, Framed};
7 7
use actix_rt::net::TcpStream;
@@ -20,15 +20,17 @@
Loading
20 20
use crate::helpers::DataFactory;
21 21
use crate::request::Request;
22 22
use crate::response::Response;
23 -
use crate::{h1, h2::Dispatcher, Protocol};
23 +
use crate::{h1, h2::Dispatcher, ConnectCallback, Extensions, Protocol};
24 24
25 -
/// `ServiceFactory` HTTP1.1/HTTP2 transport implementation
25 +
/// A `ServiceFactory` for HTTP/1.1 or HTTP/2 protocol.
26 26
pub struct HttpService<T, S, B, X = h1::ExpectHandler, U = h1::UpgradeHandler<T>> {
27 27
    srv: S,
28 28
    cfg: ServiceConfig,
29 29
    expect: X,
30 30
    upgrade: Option<U>,
31 -
    on_connect: Option<rc::Rc<dyn Fn(&T) -> Box<dyn DataFactory>>>,
31 +
    // DEPRECATED: in favor of on_connect_ext
32 +
    on_connect: Option<Rc<dyn Fn(&T) -> Box<dyn DataFactory>>>,
33 +
    on_connect_ext: Option<Rc<ConnectCallback<T>>>,
32 34
    _t: PhantomData<(T, B)>,
33 35
}
34 36
@@ -66,6 +68,7 @@
Loading
66 68
            expect: h1::ExpectHandler,
67 69
            upgrade: None,
68 70
            on_connect: None,
71 +
            on_connect_ext: None,
69 72
            _t: PhantomData,
70 73
        }
71 74
    }
@@ -81,6 +84,7 @@
Loading
81 84
            expect: h1::ExpectHandler,
82 85
            upgrade: None,
83 86
            on_connect: None,
87 +
            on_connect_ext: None,
84 88
            _t: PhantomData,
85 89
        }
86 90
    }
@@ -113,6 +117,7 @@
Loading
113 117
            srv: self.srv,
114 118
            upgrade: self.upgrade,
115 119
            on_connect: self.on_connect,
120 +
            on_connect_ext: self.on_connect_ext,
116 121
            _t: PhantomData,
117 122
        }
118 123
    }
@@ -138,18 +143,25 @@
Loading
138 143
            srv: self.srv,
139 144
            expect: self.expect,
140 145
            on_connect: self.on_connect,
146 +
            on_connect_ext: self.on_connect_ext,
141 147
            _t: PhantomData,
142 148
        }
143 149
    }
144 150
145 151
    /// Set on connect callback.
146 152
    pub(crate) fn on_connect(
147 153
        mut self,
148 -
        f: Option<rc::Rc<dyn Fn(&T) -> Box<dyn DataFactory>>>,
154 +
        f: Option<Rc<dyn Fn(&T) -> Box<dyn DataFactory>>>,
149 155
    ) -> Self {
150 156
        self.on_connect = f;
151 157
        self
152 158
    }
159 +
160 +
    /// Set connect callback with mutable access to request data container.
161 +
    pub(crate) fn on_connect_ext(mut self, f: Option<Rc<ConnectCallback<T>>>) -> Self {
162 +
        self.on_connect_ext = f;
163 +
        self
164 +
    }
153 165
}
154 166
155 167
impl<S, B, X, U> HttpService<TcpStream, S, B, X, U>
@@ -355,6 +367,7 @@
Loading
355 367
            expect: None,
356 368
            upgrade: None,
357 369
            on_connect: self.on_connect.clone(),
370 +
            on_connect_ext: self.on_connect_ext.clone(),
358 371
            cfg: self.cfg.clone(),
359 372
            _t: PhantomData,
360 373
        }
@@ -378,7 +391,8 @@
Loading
378 391
    fut_upg: Option<U::Future>,
379 392
    expect: Option<X::Service>,
380 393
    upgrade: Option<U::Service>,
381 -
    on_connect: Option<rc::Rc<dyn Fn(&T) -> Box<dyn DataFactory>>>,
394 +
    on_connect: Option<Rc<dyn Fn(&T) -> Box<dyn DataFactory>>>,
395 +
    on_connect_ext: Option<Rc<ConnectCallback<T>>>,
382 396
    cfg: ServiceConfig,
383 397
    _t: PhantomData<(T, B)>,
384 398
}
@@ -429,6 +443,7 @@
Loading
429 443
            .fut
430 444
            .poll(cx)
431 445
            .map_err(|e| log::error!("Init http service error: {:?}", e)));
446 +
432 447
        Poll::Ready(result.map(|service| {
433 448
            let this = self.as_mut().project();
434 449
            HttpServiceHandler::new(
@@ -437,6 +452,7 @@
Loading
437 452
                this.expect.take().unwrap(),
438 453
                this.upgrade.take(),
439 454
                this.on_connect.clone(),
455 +
                this.on_connect_ext.clone(),
440 456
            )
441 457
        }))
442 458
    }
@@ -448,7 +464,8 @@
Loading
448 464
    expect: CloneableService<X>,
449 465
    upgrade: Option<CloneableService<U>>,
450 466
    cfg: ServiceConfig,
451 -
    on_connect: Option<rc::Rc<dyn Fn(&T) -> Box<dyn DataFactory>>>,
467 +
    on_connect: Option<Rc<dyn Fn(&T) -> Box<dyn DataFactory>>>,
468 +
    on_connect_ext: Option<Rc<ConnectCallback<T>>>,
452 469
    _t: PhantomData<(T, B, X)>,
453 470
}
454 471
@@ -469,11 +486,13 @@
Loading
469 486
        srv: S,
470 487
        expect: X,
471 488
        upgrade: Option<U>,
472 -
        on_connect: Option<rc::Rc<dyn Fn(&T) -> Box<dyn DataFactory>>>,
489 +
        on_connect: Option<Rc<dyn Fn(&T) -> Box<dyn DataFactory>>>,
490 +
        on_connect_ext: Option<Rc<ConnectCallback<T>>>,
473 491
    ) -> HttpServiceHandler<T, S, B, X, U> {
474 492
        HttpServiceHandler {
475 493
            cfg,
476 494
            on_connect,
495 +
            on_connect_ext,
477 496
            srv: CloneableService::new(srv),
478 497
            expect: CloneableService::new(expect),
479 498
            upgrade: upgrade.map(CloneableService::new),
@@ -543,30 +562,34 @@
Loading
543 562
    }
544 563
545 564
    fn call(&mut self, (io, proto, peer_addr): Self::Request) -> Self::Future {
546 -
        let on_connect = if let Some(ref on_connect) = self.on_connect {
547 -
            Some(on_connect(&io))
548 -
        } else {
549 -
            None
550 -
        };
565 +
        let mut connect_extensions = Extensions::new();
566 +
567 +
        let deprecated_on_connect = self.on_connect.as_ref().map(|handler| handler(&io));
568 +
        if let Some(ref handler) = self.on_connect_ext {
569 +
            handler(&io, &mut connect_extensions);
570 +
        }
551 571
552 572
        match proto {
553 573
            Protocol::Http2 => HttpServiceHandlerResponse {
554 574
                state: State::H2Handshake(Some((
555 575
                    server::handshake(io),
556 576
                    self.cfg.clone(),
557 577
                    self.srv.clone(),
558 -
                    on_connect,
578 +
                    deprecated_on_connect,
579 +
                    connect_extensions,
559 580
                    peer_addr,
560 581
                ))),
561 582
            },
583 +
562 584
            Protocol::Http1 => HttpServiceHandlerResponse {
563 585
                state: State::H1(h1::Dispatcher::new(
564 586
                    io,
565 587
                    self.cfg.clone(),
566 588
                    self.srv.clone(),
567 589
                    self.expect.clone(),
568 590
                    self.upgrade.clone(),
569 -
                    on_connect,
591 +
                    deprecated_on_connect,
592 +
                    connect_extensions,
570 593
                    peer_addr,
571 594
                )),
572 595
            },
@@ -595,6 +618,7 @@
Loading
595 618
            ServiceConfig,
596 619
            CloneableService<S>,
597 620
            Option<Box<dyn DataFactory>>,
621 +
            Extensions,
598 622
            Option<net::SocketAddr>,
599 623
        )>,
600 624
    ),
@@ -670,9 +694,16 @@
Loading
670 694
                } else {
671 695
                    panic!()
672 696
                };
673 -
                let (_, cfg, srv, on_connect, peer_addr) = data.take().unwrap();
697 +
                let (_, cfg, srv, on_connect, on_connect_data, peer_addr) =
698 +
                    data.take().unwrap();
674 699
                self.set(State::H2(Dispatcher::new(
675 -
                    srv, conn, on_connect, cfg, None, peer_addr,
700 +
                    srv,
701 +
                    conn,
702 +
                    on_connect,
703 +
                    on_connect_data,
704 +
                    cfg,
705 +
                    None,
706 +
                    peer_addr,
676 707
                )));
677 708
                self.poll(cx)
678 709
            }

Click to load this diff.
Loading diff...

Click to load this diff.
Loading diff...

Click to load this diff.
Loading diff...

Click to load this diff.
Loading diff...

Learn more Showing 1 files with coverage changes found.

Changes in actix-http/src/request.rs
-2
+2
Loading file...
Files Coverage
actix-files/src 0.00%
actix-http/src 0.15% 38.02%
actix-multipart/src 0.00%
actix-web-actors/src 0.00%
awc/src 17.98%
src -0.42% 86.61%
tests 100.00%
actix-web-codegen/src/route.rs 0.00%
Project Totals (125 files) 53.89%
Loading