分享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, 源代码

相关文章

在 Go 项目中使用 LevelDB 进行数据存储

LevelDB 是一个由 Google 开发的高性能键值存储库,广泛应用于需要快速读写操作的场景。本文将介绍如何在 Go 项目中使用 LevelDB 作为数据存储,并通过示例代码展示如何初始化数...

详解Go语言依赖注入工具wire最佳实践介绍与使用

wire是一个强大的依赖注入工具,通过代码生成的方式实现了高效的依赖注入。本文详细介绍了wire的入门级和高级使用技巧,并通过示例代码展示了其强大的功能。无论是简单的依赖注入,还是复杂的依赖图生...

Go语言中copy命令讲解 切片之间复制元素

在Go语言中,copy函数是一个非常常用的内置函数,用于在切片(slice)之间复制元素。理解copy函数的用法和机制对于高效处理数据操作至关重要1. copy函数的基本用法copy函数的基本语...

深入理解 Go 语言中的 goto:用法与最佳实践

在学习编程语言时,goto 一直是一个颇具争议的概念。它常常因为“跳跃式”的行为被认为会让代码混乱且难以维护,但在 Go 语言中,goto 被保留并提供了一些实际的应用场景。今天我们将深入探讨 ...

Go并发编程与调度器及并发模式详解

Go语言以其简洁的语法和强大的并发能力,成为现代网络编程和微服务架构的热门选择。本文将深入探讨Go的并发编程模型,调度器的工作机制,以及多种并发模式的实现和应用,帮助开发者更好地理解并发编程的设...

图片Base64编码

CSR生成

图片无损放大

图片占位符

Excel拆分文件