swift-server / swift-server/async-http-client

Proxy server implementation example needed

Open
#757 3 comments 0 reactions 0 assignees View on GitHub

Nobody has claimed this yet.

Dominant language
Swift
Stars
1.1k
Forks
156
PR merge metrics
No merged PRs in 30d

Description

Hello,
I need a proxy server endpoint for my Vapor project. The goal is to get the endpoint, which will take a URL as a parameter, get the page of that URL, modify it, and return it to the user. I've searched for an example here and over the internet but had no luck. Can I get the fully working thing I am trying to do with async-http-client? I need to proxy a page with JS, Google authorization, so I need to forward cookies etc.

The only useful thing I have found was the implementation of the proxy for the different Swift serverside framework - Hummingbird. It also uses async-http-client and the author says, that the implementation in Vapor will look similar.

Well, I am not a pro but here is what I have at the moment:

Proxy Middleware:

func respond(to request: Vapor.Request, chainingTo next: Vapor.AsyncResponder) async throws -> Vapor.Response {
        // Convert to HTTPClient.Request
        let ahcRequest = try await request.ahcRequest(host: target)
        
        // Execute the request using httpClient
        let clientResponse = httpClient.execute(request: ahcRequest)
        
        // Convert HTTPClient.Response to Vapor.Response
        var vaporResponse = try await clientResponse.get().vaporResponse
        
        return vaporResponse
}

HTTP.Response -> Vapor.Response:

extension HTTPClient.Response {
    var vaporResponse: Response {
        var headers = HTTPHeaders()
        self.headers.forEach { headers.add(name: $0.name, value: $0.value) }
        
        let body: Response.Body
        if let buffer = self.body {
            body = .init(buffer: buffer)
        } else {
            body = .empty
        }
        
        return Response(
            status: .init(statusCode: Int(self.status.code)),
            headers: headers,
            body: body
        )
    }
}

Vapor.Request -> async-http-client.Request:

extension Request {
    func ahcRequest(host: String) async throws -> HTTPClient.Request {
        let collectedBuffer = try await self.body.collect(max: 1024 * 1024).get()
        
        return try HTTPClient.Request(
            url: host,
            method: self.method,
            headers: self.headers,
            body: collectedBuffer.map { HTTPClient.Body.byteBuffer($0) }
        )
    }
}

When I try to proxy the simple webpage with only HTML written - it works. But something more complicated fails.
If you have an example of how I can implement a working proxy for the modern websites, please share it with me.

Thanks.

Contributor guide

Open the contributing guide

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

Research direction

Review the Vapor middleware and the HTTPClient.Request/Response conversion examples in the issue, then compare them with the Hummingbird proxy implementation mentioned there. Determine the scope of a documented async-http-client proxy example, including the requested handling of JavaScript, authorization, and forwarded cookies; done would be a clearly scoped, working example.

Written by the indexing model from the issue text.

Assessment

Tech stack
swift
Domain
api, backend, documentation
Issue type
Documentation
Difficulty
5/5
Estimated time
Over a week
Activity status
Stale
Clarity
Needs clarification
Newbie friendliness
25/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.