first versiom
This commit is contained in:
136
main.go
Normal file
136
main.go
Normal file
@@ -0,0 +1,136 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"net/http"
|
||||
"net/url"
|
||||
"regexp"
|
||||
"strings"
|
||||
)
|
||||
|
||||
const (
|
||||
PREFIX = "https://gh.ncc.cx/"
|
||||
|
||||
exp1 = `^(?:https?:\/\/)?github\.com\/.+?\/.+?\/(?:releases|archive)\/.*$`
|
||||
exp2 = `^(?:https?:\/\/)?github\.com\/.+?\/.+?\/(?:blob|raw)\/.*$`
|
||||
exp3 = `^(?:https?:\/\/)?github\.com\/.+?\/.+?\/(?:info|git-).*$`
|
||||
exp4 = `^(?:https?:\/\/)?raw\.(?:githubusercontent|github)\.com\/.+?\/.+?\/.+?\/.+$`
|
||||
exp5 = `^(?:https?:\/\/)?gist\.(?:githubusercontent|github)\.com\/.+?\/.+?\/.+$`
|
||||
exp6 = `^(?:https?:\/\/)?github\.com\/.+?\/.+?\/tags.*$`
|
||||
)
|
||||
|
||||
func checkUrl(u string) bool {
|
||||
for _, exp := range []string{exp1, exp2, exp3, exp4, exp5, exp6} {
|
||||
if ok, e := regexp.MatchString(exp, u); ok {
|
||||
return true
|
||||
} else if e != nil {
|
||||
fmt.Println(e)
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
func fetchHandler(w http.ResponseWriter, r *http.Request) {
|
||||
path := r.URL.Path
|
||||
if !strings.Contains(path, "/") {
|
||||
w.WriteHeader(http.StatusNotFound)
|
||||
return
|
||||
}
|
||||
|
||||
path = strings.TrimPrefix(path, "/") // 获取到的URL
|
||||
path = strings.Replace(path, "https:/", "https://", 1)
|
||||
|
||||
u, _ := url.Parse(path)
|
||||
|
||||
match1, _ := regexp.MatchString(exp1, u.String())
|
||||
match2, _ := regexp.MatchString(exp2, u.String())
|
||||
match3, _ := regexp.MatchString(exp3, u.String())
|
||||
match4, _ := regexp.MatchString(exp4, u.String())
|
||||
match5, _ := regexp.MatchString(exp5, u.String())
|
||||
match6, _ := regexp.MatchString(exp6, u.String())
|
||||
|
||||
if match1 || match5 || match6 || match3 || match4 {
|
||||
httpHandler(w, r, path)
|
||||
return
|
||||
} else if match2 {
|
||||
path = strings.ReplaceAll(u.Path, "/blob/", "/raw/")
|
||||
httpHandler(w, r, path)
|
||||
return
|
||||
}
|
||||
|
||||
http.Error(w, fmt.Sprintf("%s is not support", path), http.StatusOK)
|
||||
}
|
||||
|
||||
func httpHandler(w http.ResponseWriter, r *http.Request, pathname string) {
|
||||
reqHdrRaw := r.Header
|
||||
|
||||
if r.Method == http.MethodOptions && reqHdrRaw.Get("access-control-request-headers") != "" {
|
||||
w.Header().Set("Access-Control-Allow-Origin", "*")
|
||||
w.Header().Set("Access-Control-Allow-Methods", "GET, POST, PUT, PATCH, TRACE, DELETE, HEAD, OPTIONS")
|
||||
w.Header().Set("Access-Control-Max-Age", "1728000")
|
||||
w.WriteHeader(http.StatusNoContent)
|
||||
return
|
||||
}
|
||||
|
||||
if strings.HasPrefix(pathname, "github") {
|
||||
pathname = "https://" + pathname
|
||||
}
|
||||
|
||||
client := &http.Client{
|
||||
CheckRedirect: func(req *http.Request, via []*http.Request) error {
|
||||
return http.ErrUseLastResponse
|
||||
},
|
||||
}
|
||||
|
||||
proxy(w, r, client, pathname)
|
||||
}
|
||||
|
||||
func proxy(w http.ResponseWriter, r *http.Request, client *http.Client, pathname string) {
|
||||
r.URL, _ = url.Parse(pathname)
|
||||
req, _ := http.NewRequest(r.Method, r.URL.String(), r.Body)
|
||||
for k, v := range r.Header {
|
||||
req.Header.Set(k, v[0])
|
||||
}
|
||||
for _, value := range r.Cookies() {
|
||||
w.Header().Add(value.Name, value.Value)
|
||||
}
|
||||
res, e := client.Do(req)
|
||||
if e != nil {
|
||||
http.Error(w, e.Error(), http.StatusOK)
|
||||
return
|
||||
}
|
||||
|
||||
if res.Header.Get("location") != "" {
|
||||
location := res.Header.Get("location")
|
||||
if checkUrl(location) {
|
||||
res.Header.Set("location", PREFIX+location)
|
||||
} else {
|
||||
newReq, _ := http.NewRequest(r.Method, location, res.Body)
|
||||
proxy(w, newReq, http.DefaultClient, location)
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
res.Header.Set("Access-Control-Expose-Headers", "*")
|
||||
res.Header.Set("Access-Control-Allow-Origin", "*")
|
||||
|
||||
res.Header.Del("Content-Security-Policy")
|
||||
res.Header.Del("Content-Security-Policy-Report-Only")
|
||||
res.Header.Del("Clear-Site-Data")
|
||||
|
||||
w.WriteHeader(res.StatusCode)
|
||||
for k, v := range res.Header {
|
||||
w.Header().Set(k, strings.Join(v, ","))
|
||||
}
|
||||
_ = res.Write(w)
|
||||
}
|
||||
|
||||
func main() {
|
||||
http.HandleFunc("/", fetchHandler)
|
||||
|
||||
err := http.ListenAndServe(fmt.Sprintf(":%d", 8091), nil)
|
||||
if err != nil {
|
||||
fmt.Println("run server error: ", err)
|
||||
return
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user