Implementing HTTP proxy that can support HTTPS requests by using actix-web


#1

Hello,
I would like to write a simple HTTP proxy server that can handle HTTPS requests too.
Based on 7231 RFC server must support CONNECT header.
I could not find any reference in Actix-web that point out CONNECT header.
Would someone please give a hint for implementing CONNECT functionality.


I the above, I have no idea to handling this.


It must support something like this :

P.S.: I did ask this question in actix-web issues but nobody doesn’t answer me yet, because, I have a little time, I did ask it here too.


#2

You need to use bind_tls rather than bind to enable ssl connections to the actix server: https://docs.rs/actix-web/0.7.18/actix_web/server/struct.HttpServer.html#method.bind_ssl. Here’s some example code for creating the acceptor to pass to this: https://github.com/actix/actix-web/blob/4e7fac08b9675dad2965611e1c33cc734603de4f/tests/test_server.rs#L1027-L1033

This will require enabling actix’s tls feature - you can do this with actix = { version = "...", features = ["tls"] } in Cargo.toml.


#3

Thank you for your response, I think my question was a little ambiguous, I edited my question.
I will explain my problem: my question is about an HTTP proxy server that can handle HTTPS requests too.
AFAIK, for implementing this we don’t need to setup SSL/TLS on the server, instead of that we must setup HTTP tunneling by using CONNECT header.
By using CONNECT header we can transfer non-HTTP requests over HTTP that will use in proxy servers.


CONNECT header has two major part, as you can see in the above photo, the first part is about HTTP request and in fact connection request, if the connection was successful, the second part will use that is binary data.


In actix I couldn’t find any solution to implementing second part (for sending binary data after an HTTP request in same connection). in fact, web-socket is something like this.


As a result, I’m finding for a solution to giving control of TcpStream after actix response for manually handling this.


Sorry for my bad English

I would like to say sorry for my English, I’m an ESL (English as a Second Language) person, If is somewhere In sentences, please tell me to describe that.


#4

I couldn’t find any easy solution for you.
Actix-Web is built on Actix and probably you can use Actix’s context to implementing CONNECT by yourself, If you haven’t enough time to wait for an easy solution or you are not able to implement this, I’d suggest you try other solutions like Hyper-proxy, Actix’s family are great libraries, but at this time, it hasn’t a hyperactive community and probably you can not find your answer.


#5

Thank you for your response, In my situation changing library is impossible.
My company is implementing an application that major web activities are on Actix-web and a simple part of that must work hybrid (both of the proxy server and web server on the same port), so I think it’s not possible to combining actix-web and hyper-proxy.

I’m not familiar to actix’s context, could you please give a hint for implementing this?


#6

You can combine actix-web and hyper proxy by using to a proxy (such as nginx).

Unfortunately, I’m not fluent on Actix, I had a look at ws/context.rs, due to the similarity of WS and connect tunnel, probably it can helping you.


#7

I’m not allowed to use external resources, hence Nginx and similar solutions aren’t fit of me.


I did check the ws/context.rs page previously, I couldn’t understand how it works.


#8

Thanks for explaining it more! I definitely misunderstood the question. Unfortunately I’m not really an expert on HTTP internals, but I can probably help with the actix API.

If you have the headers sent correctly, and want to send more binary data, have you tried using HttpResponseBuilder::body?

I think using a Body::Actor with HttpContext will let you dynamically return further binary data.

Something like

struct ProxyingResponse {
    // ...
}

impl Actor for ProxyingResponse {
    type Context = HttpContext<Self, ()>;

    // could implement the 'started' method here to have some code run when this actor is created
}

// can use messages to send data into the ProxyingResponse to be returned to the request
impl Handler<MessageType> for ProxyingResponse {
    type Result: Something;
    fn handle(&mut self, msg: MessageType, ctx: &mut HttpContext<Self, ()>) -> Self::Result {
        // key is that in here, we have access to 'ctx'
        // for example, we can call
        ctx.write(vec![1, 2, 3]);
    }
}

fn index(req: HttpRequest) -> HttpResponse {
    let context = HttpContext::create(req, ProxyingResponse::new());
    HttpResponse::build(StatusCode::OK)
        .body(Body::Actor(Box::new(context))
}

You might be able to combine this with using the payload method on HttpRequest provided by the HttpMessage implementation in order to get read more binary data from the stream? I think that Payload could then be read as a futures::Stream.

This definitely isn’t a complete answer, but it might be useful regardless. I think that all the pieces are here in actix, and we just need to figure out how to plumb them together and make it all work. I’m not an expert on what needs to be done to implement the proxy part, but hopefully this can help with the using-actix part.


#9

I think it’s exact what I need.
Unfortunately I’m not good at Actix and i can not understand your sample code very well.
I’m reading actix documentations and If i had a problem to understanding your code, I will ask you again in this topic.

Thank you so much. :hibiscus::hibiscus: