分享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并发编程与调度器及并发模式详解

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

Go语言中sync.Pool详解

sync.Pool 是 Go 语言标准库中的一个数据结构,用于提供高效的对象池。它的主要作用是缓存临时对象,以减少内存分配和垃圾回收的开销。sync.Pool 特别适合用于存储短生命周期的对象,...

Go 中的并发 Map:使用sync.Map及其他实现方法

在 Go 语言中,并发编程是一个核心特性,能够高效地处理多个 goroutine 的并发执行。为了安全地在多个 goroutine 中共享数据,Go 提供了多种同步机制,其中之一就是线程安全的 ...

Go语言中的单例模式及其实现sync.Once

在软件开发中,单例模式是一种确保一个类只有一个实例的设计模式。在 Go 语言中,sync.Once 是实现单例模式的强大工具,它确保某个操作只被执行一次,适合在多线程环境中使用。本篇文章将详细介...

详解Go条件变量cond的使用

在 Go 语言中,条件变量(sync.Cond)是一种用于实现线程间同步的工具。它允许一个或多个 goroutine 等待某个条件的发生。条件变量通常与互斥锁(sync.Mutex)结合使用,以...

Go语言任务编排好帮手WaitGroup

在并发编程中,任务的协调与管理至关重要。在Go语言中,sync.WaitGroup是一个非常实用的工具,能够帮助我们等待一组任务完成。本文将详细讲解WaitGroup的使用方法、实现原理、使用陷...

Go 语言中的读写锁RWMutex详解

在现代并发编程中,如何高效、安全地管理共享资源是一项重要的挑战。Go 语言的 sync 包提供了多种同步原语,其中 RWMutex(读写锁)特别适合于读多写少的场景。本文将深入探讨 RWMute...

图片Base64编码

CSR生成

图片无损放大

图片占位符

Excel拆分文件