分享Go语言实现的GitHub.com加速及nginx配置

编译Go项目后,默认端口8080
使用方法如下,假设你的域名是x.com, 那么你拉取项目的时候就可以参考如下...

git clone https://x.com/github.com/user/info.git

git clone https://x.com/https://github.com/user/info.git

https://x.com/github.com/user/info/blob/main/demo.txt

https://x.com/https://github.com/user/info/blob/main/demo.txt

以下是Nginx反代配置

location / {
    proxy_pass http://127.0.0.1:8080;
    proxy_set_header Host $host;
    proxy_set_header X-Real-IP $remote_addr;
    proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
    proxy_set_header X-Forwarded-Proto $scheme;
}

main.go源码

package main

import (
    "fmt"
    "io"
    "net/http"
    "regexp"
    "strconv"
    "strings"

    "github.com/gin-gonic/gin"
)

const (
    sizeLimit = 1024 * 1024 * 1024 * 1
    host      = "127.0.0.1"
    port      = 8080
)

var (
    exps = []*regexp.Regexp{
        regexp.MustCompile(`^(?:https?://)?github\.com/([^/]+)/([^/]+)/(?:releases|archive)/.*$`),
        regexp.MustCompile(`^(?:https?://)?github\.com/([^/]+)/([^/]+)/(?:blob|raw)/.*$`),
        regexp.MustCompile(`^(?:https?://)?github\.com/([^/]+)/([^/]+)/(?:info|git-).*$`),
        regexp.MustCompile(`^(?:https?://)?raw\.github(?:usercontent|)\.com/([^/]+)/([^/]+)/.+?/.+$`),
        regexp.MustCompile(`^(?:https?://)?gist\.github\.com/([^/]+)/.+?/.+$`),
    }
)

func main() {
    gin.SetMode(gin.ReleaseMode)
    router := gin.Default()

    // 根路径重定向到自己的主站
    router.GET("/", func(c *gin.Context) {
        c.Redirect(http.StatusMovedPermanently, "https://lvtao.net")
    })

    router.NoRoute(handler)

    err := router.Run(fmt.Sprintf("%s:%d", host, port))
    if err != nil {
        fmt.Printf("Error starting server: %v\n", err)
    }
}

func handler(c *gin.Context) {
    rawPath := strings.TrimPrefix(c.Request.URL.RequestURI(), "/")
    re := regexp.MustCompile(`^(http:|https:)?/?/?(.*)`)
    matches := re.FindStringSubmatch(rawPath)

    rawPath = "https://" + matches[2]

    matches = checkURL(rawPath)
    if matches == nil {
        c.String(http.StatusForbidden, "Invalid input.")
        return
    }

    if exps[1].MatchString(rawPath) {
        rawPath = strings.Replace(rawPath, "/blob/", "/raw/", 1)
    }

    proxy(c, rawPath)
}

func proxy(c *gin.Context, u string) {
    req, err := http.NewRequest(c.Request.Method, u, c.Request.Body)
    if err != nil {
        c.String(http.StatusInternalServerError, fmt.Sprintf("server error %v", err))
        return
    }

    for key, values := range c.Request.Header {
        for _, value := range values {
            req.Header.Add(key, value)
        }
    }
    req.Header.Del("Host")

    resp, err := http.DefaultClient.Do(req)
    if err != nil {
        c.String(http.StatusInternalServerError, fmt.Sprintf("server error %v", err))
        return
    }
    defer resp.Body.Close()

    if contentLength, ok := resp.Header["Content-Length"]; ok {
        if size, err := strconv.Atoi(contentLength[0]); err == nil && size > sizeLimit {
            finalURL := resp.Request.URL.String()
            c.Redirect(http.StatusMovedPermanently, finalURL)
            return
        }
    }

    resp.Header.Del("Content-Security-Policy")
    resp.Header.Del("Referrer-Policy")
    resp.Header.Del("Strict-Transport-Security")

    for key, values := range resp.Header {
        for _, value := range values {
            c.Header(key, value)
        }
    }

    c.Status(resp.StatusCode)
    if _, err := io.Copy(c.Writer, resp.Body); err != nil {
        return
    }
}

func checkURL(u string) []string {
    for _, exp := range exps {
        if matches := exp.FindStringSubmatch(u); matches != nil {
            return matches[1:]
        }
    }
    return nil
}

标签: Go, Nginx

相关文章

nginx自动识别移动端配置不同的root目录

要在 Nginx 中实现根据设备类型(PC 和移动端)动态设置不同的 root 目录,直接修改 root 目录是不被允许的。为了解决这个问题,最有效的方法是通过 location 块分别处理 P...

Go 开发中的go:embed应用与最佳实践

go:embed 使用介绍go:embed 是 Go 语言的一项编译器指令,它允许在编译时将任意文件或目录嵌入到 Go 的二进制文件中。通过这种方式,开发者可以在不依赖外部文件的情况下直接在代码...

图片Base64编码

CSR生成

图片无损放大

图片占位符

Excel拆分文件