SoFunction
Updated on 2025-03-05

A simple Golang implementation of HTTP Proxy method

Recently, because I changed my Mac, my previous Linux is basically no longer used, but my SS proxy still needs to be used. Everyone knows that SS proxy is a very NB socks proxy tool, but because it is Socks, it is inconvenient to use HTTP proxy.

In the past, when I was under Linux, I would install a Privoxy to convert the socks proxy into an HTTP proxy, which is also more convenient to start. However, it is difficult to use Privoxy installed with Brew on Mac. In addition, one of them had an idea before, and one software did the socks and HTTP proxy, so that there was no need to install a separate software to convert.

Just start doing it when you think about it. I have basically never done too much network programming before. I am also studying Go recently, and I just practice my skills.

Here we mainly talk about the tunnel connection established using the CONNECT method in the HTTP/1.1 protocol to implement HTTP Proxy. The advantage of this kind of proxy is that it does not need to know the data requested by the client, but only needs to forward it intact. It is very convenient for processing HTTPS requests. You can implement the proxy without parsing its content.

Start proxy listening

To do an HTTP Proxy, we need to start a server and listen to a port to receive client requests. Golang provides us with a powerful net package for us to use, and it is very convenient for us to start a proxy server to listen.

  l, err := ("tcp", ":8080")
  if err != nil {
    (err)
  }

For the above agent, we implement a server that listens on port 8080. We do not write an IP address here, and listen on all IP addresses by default. If you only want this machine to work, you can use 127.0.0.1:8080, so that the machine cannot access your proxy server.

Listen to receive proxy requests

Once the proxy server is started, we can start to be unable to accept the proxy request. Only with the request can we do further processing.

  for {
    client, err := ()
    if err != nil {
      (err)
    }

    go handleClientRequest(client)
  }

The Accept method of the Listener interface will accept connection data sent by the client. This is a blocking method. If the client does not send connection data, it will block and wait. The received connection data will be immediately handed over to the handleClientRequest method for processing. The purpose of using a go keyword here to open a goroutine is to not block the client's reception, and the proxy server can immediately receive the next connection request.

Parse the request to get the IP and port to access

With the client's proxy request, we have to extract the IP and port of the remote host that the client wants to access from the request, so that our proxy server can establish a connection with the remote host and forward the proxy.

The header information of the HTTP protocol contains the host name (IP) and port information we need, and it is plain text. The protocol is very standardized, similar to:

CONNECT :443 HTTP/1.1
Host: :443
Proxy-Connection: keep-alive
User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_0) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/55.0.2883.95 Safari/537.36

You can see that the information we need in the first line is separated by spaces. The first part CONNECT is the request method, here is CONNECT. In addition, there are GET, POST, etc., which are all standard methods of the HTTP protocol.

The second part is the URL. The http request only has host and port. The http request is a completed url. I will see a sample later and you will understand.

The third part is the HTTP protocol and version, so we don’t need to pay much attention to this.

The above is a https request. Let's take a look at http:

GET / HTTP/1.1
Host: 
Proxy-Connection: keep-alive
Upgrade-Insecure-Requests: 1
User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_0) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/55.0.2883.95 Safari/537.36

You can see http, without a port number (default is 80); there is more schame – http:// than https.

With analysis, we can get the requested url and method information from the HTTP header information.


  var b [1024]byte
  n, err := (b[:])
  if err != nil {
    (err)
    return
  }
  var method, host, address string
  (string(b[:(b[:], '\n')]), "%s%s", &method, &host)
  hostPortURL, err := (host)
  if err != nil {
    (err)
    return
  
  }

Then we need to further parse the URL to obtain the remote server information we need


  if  == "443" { // https access    address =  + ":443"
  } else { // http access    if (, ":") == -1 { //host does not have port, default 80      address =  + ":80"
    } else {
      address = 
    }
  }

This completes the information to request the server. They may be in the following formats

ip:port
hostname:port
domainname:port

It is possible to be ip (v4orv6), it may be the host name (intranet), it may be the domain name (dns analysis)

Establish a connection between a proxy server and a remote server

With the information of the remote server, you can dial up and establish a connection. Only with the connection can you communicate.

  //After obtaining the requested host and port, start dialing  server, err := ("tcp", address)
  if err != nil {
    (err)
    return
  }

Data Forwarding

After the dial is successful, the data proxy can be transmitted.

if method == "CONNECT" {
    (client, "HTTP/1.1 200 Connection established\r\n")
  } else {
    (b[:n])
  }
  //Forward  go (server, client)
  (client, server)

There is a separate response to the CONNECT method. The client says that the connection is to be established, and the proxy server needs to respond and establish it before it can request access like HTTP.

Run a foreign VPS on

At this point, our proxy server has been fully developed, and the following is the complete source code:

package main

import (
  "bytes"
  "fmt"
  "io"
  "log"
  "net"
  "net/url"
  "strings"
)

func main() {
  (|)
  l, err := ("tcp", ":8081")
  if err != nil {
    (err)
  }

  for {
    client, err := ()
    if err != nil {
      (err)
    }

    go handleClientRequest(client)
  }
}

func handleClientRequest(client ) {
  if client == nil {
    return
  }
  defer ()

  var b [1024]byte
  n, err := (b[:])
  if err != nil {
    (err)
    return
  }
  var method, host, address string
  (string(b[:(b[:], '\n')]), "%s%s", &method, &host)
  hostPortURL, err := (host)
  if err != nil {
    (err)
    return
  }

  if  == "443" { // https access    address =  + ":443"
  } else { // http access    if (, ":") == -1 { //host does not have port, default 80      address =  + ":80"
    } else {
      address = 
    }
  }

  //After obtaining the requested host and port, start dialing  server, err := ("tcp", address)
  if err != nil {
    (err)
    return
  }
  if method == "CONNECT" {
    (client, "HTTP/1.1 200 Connection established\r\n")
  } else {
    (b[:n])
  }
  //Forward  go (server, client)
  (client, server)
}

Compile the source code, then put it on your foreign VPS, configure the HTTP proxy on your own machine, and you can access it everywhere and be free.

The above article is a simple HTTP Proxy method implemented by Golang. It is all the content I share with you. I hope you can give you a reference and I hope you can support me more.