1
0
Fork 0
promty/proxy/main.go

145 lines
3.5 KiB
Go
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

package main
import (
"bytes"
"compress/gzip"
"fmt"
"io"
"net/http"
"net/http/httputil"
"net/url"
"os"
"regexp"
"strings"
)
func main() {
proxy := &httputil.ReverseProxy{
Rewrite: func(r *httputil.ProxyRequest) {
host, _ := Yadro2Kernel(r.In.Host, true)
url, _ := url.Parse("https://" + host)
r.SetURL(url)
// We only support gzip decoding
r.Out.Header.Set("Accept-Encoding", "gzip")
r.Out.Header.Set("User-Agent", "ядро.орг/1.0")
},
ModifyResponse: func(r *http.Response) error {
// Disable security policy because of the domain restrictions.
r.Header.Del("Content-Security-Policy")
// Skip non-html pages.
contentType := r.Header.Get("Content-Type")
if !strings.HasPrefix(contentType, "text/") {
return nil
}
r.Header.Set("Content-Type", contentType+";charset=utf-8")
// Read response body into data. If body is encoded, decode it.
var data []byte
switch r.Header.Get("Content-Encoding") {
case "gzip":
reader, _ := gzip.NewReader(r.Body)
data, _ = io.ReadAll(reader)
r.Body.Close()
default:
data, _ = io.ReadAll(r.Body)
r.Body.Close()
}
// Rewrite 30x redirect location
locHeader := r.Header.Get("Location")
if locHeader != "" {
re := regexp.MustCompile(`https?:\/\/[A-Za-z\-\.]*.?kernel\.org\/`)
r.Header.Set("Location", string(re.ReplaceAllFunc([]byte(locHeader), func(original_raw []byte) []byte {
kernel := strings.ToLower(string(original_raw))
kernel = strings.TrimPrefix(kernel, "https://")
kernel = strings.TrimPrefix(kernel, "http://")
kernel = strings.TrimPrefix(kernel, "www.")
kernel = strings.TrimSuffix(kernel, "/")
yadro, exists := Kernel2Yadro(kernel)
if !exists {
fmt.Println("Missing:", kernel)
return original_raw
}
return []byte("http://" + yadro + "/") // TODO: https
})))
}
// Modify the response.
data = modifyResponse(data)
// Remove headers that mess with body encoding and set the body.
r.Header.Del("Content-Encoding")
r.Header.Del("Content-Length")
r.Body = io.NopCloser(bytes.NewReader(data))
return nil
},
}
http.ListenAndServe("0.0.0.0:80", proxy)
}
func replaceDomains(response []byte) []byte {
re := regexp.MustCompile(`(?i)[A-Za-z\-\.]*\.?kernel\.org`)
response = re.ReplaceAllFunc(response, func(original_raw []byte) []byte {
kernel := strings.ToLower(string(original_raw))
// Strip `www.`
kernel = strings.TrimPrefix(kernel, "www.")
yadro, exists := Kernel2Yadro(kernel)
if !exists {
fmt.Println("Missing:", kernel)
return original_raw
}
return []byte(yadro)
})
response = bytes.ReplaceAll(response, []byte("%3F"), []byte("?"))
response = bytes.ReplaceAll(response, []byte("%26"), []byte("&"))
response = bytes.ReplaceAll(response, []byte("https"), []byte("http")) // TODO: TEMP
return response
}
func translateWithPromtPuppies(response []byte) []byte {
// Don't try to translate empty body (30x, etc)
if len(response) == 0 {
return response
}
req, _ := http.NewRequest("POST", "http://caddy:9000/translate", bytes.NewReader(response))
req.Header.Add("Content-Type", "text/html")
resp, err := http.DefaultClient.Do(req)
if err != nil {
fmt.Fprintln(os.Stderr, "Error in first", err)
return []byte{0}
}
response, _ = io.ReadAll(resp.Body)
resp.Body.Close()
return response
}
func modifyResponse(response []byte) []byte {
response = translateWithPromtPuppies(response)
response = replaceDomains(response)
return response
}