Files
vServer/Backend/WebServer/handler.go
Falknat 752f294392 Alias WildCard
Возможность добавлять Alias по маске WildCard
2025-10-03 01:59:56 +07:00

286 lines
10 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 webserver
import (
"net/http"
"os"
"strings"
"vServer/Backend/config"
tools "vServer/Backend/tools"
)
func StartHandler() {
http.HandleFunc("/", handler)
}
// Проверка wildcard паттерна для alias
func matchWildcardAlias(pattern, host string) bool {
// Если нет звёздочки - точное совпадение
if !strings.Contains(pattern, "*") {
return pattern == host
}
// Поддержка wildcard: *.example.com, example.*, *example*, *
// Заменяем * на регулярное выражение
pattern = strings.ReplaceAll(pattern, ".", "\\.")
pattern = strings.ReplaceAll(pattern, "*", ".*")
pattern = "^" + pattern + "$"
// Простая проверка без regexp (более быстрая)
return matchSimplePattern(pattern, host)
}
// Простая проверка паттерна (без использования regexp для скорости)
func matchSimplePattern(pattern, host string) bool {
// Убираем ^ и $ добавленные выше
pattern = strings.TrimPrefix(pattern, "^")
pattern = strings.TrimSuffix(pattern, "$")
// Если паттерн = .* (любой хост)
if pattern == ".*" {
return true
}
// Разбиваем паттерн на части по .*
parts := strings.Split(pattern, ".*")
// Проверяем каждую часть
currentPos := 0
for i, part := range parts {
if part == "" {
continue
}
// Ищем часть в хосте начиная с текущей позиции
idx := strings.Index(host[currentPos:], part)
if idx == -1 {
return false
}
// Для первой части проверяем что она в начале (если паттерн не начинается с *)
if i == 0 && !strings.HasPrefix(pattern, ".*") {
if idx != 0 {
return false
}
}
// Для последней части проверяем что она в конце (если паттерн не кончается на *)
if i == len(parts)-1 && !strings.HasSuffix(pattern, ".*") {
if currentPos+idx+len(part) != len(host) {
return false
}
}
currentPos += idx + len(part)
}
return true
}
func Alias_check(r *http.Request) (alias_found bool, host string) {
alias_found = false
for _, site := range config.ConfigData.Site_www {
for _, alias := range site.Alias {
// Поддержка wildcard паттернов
if matchWildcardAlias(alias, r.Host) {
alias_found = true
return alias_found, site.Host
} else {
alias_found = false
}
}
}
return alias_found, ""
}
func Alias_Run(r *http.Request) (rhost string) {
var host string
host = r.Host
alias_check, alias := Alias_check(r)
if alias_check {
host = alias
}
return host
}
// Получает список root_file для сайта из конфигурации
func getRootFiles(host string) []string {
for _, site := range config.ConfigData.Site_www {
if site.Host == host {
if site.Root_file != "" {
// Разделяем по запятой и убираем пробелы
files := strings.Split(site.Root_file, ",")
var cleanFiles []string
for _, file := range files {
cleanFile := strings.TrimSpace(file)
if cleanFile != "" {
cleanFiles = append(cleanFiles, cleanFile)
}
}
if len(cleanFiles) > 0 {
return cleanFiles
}
}
// Если не указан, используем index.html как fallback
return []string{"index.html"}
}
}
// Если сайт не найден в конфиге, используем index.html
return []string{"index.html"}
}
// Находит первый существующий root файл из списка
func findExistingRootFile(host string, dirPath string) (string, bool) {
rootFiles := getRootFiles(host)
basePath := "WebServer/www/" + host + "/public_www" + dirPath
for _, rootFile := range rootFiles {
fullPath := basePath + rootFile
if _, err := os.Stat(fullPath); err == nil {
return rootFile, true
}
}
return "", false
}
// Проверяет включен ли роутинг через root файл для сайта
func isRootFileRoutingEnabled(host string) bool {
for _, site := range config.ConfigData.Site_www {
if site.Host == host {
return site.Root_file_routing
}
}
// По умолчанию роутинг выключен
return false
}
// Проверка vAccess с обработкой ошибки
// Возвращает true если доступ разрешён, false если заблокирован
func checkVAccessAndHandle(w http.ResponseWriter, r *http.Request, filePath string, host string) bool {
accessAllowed, errorPage := CheckVAccess(filePath, host, r)
if !accessAllowed {
HandleVAccessError(w, r, errorPage, host)
tools.Logs_file(2, "vAccess", "🚫 Доступ запрещён vAccess: "+r.RemoteAddr+" → "+r.Host+filePath+" (error: "+errorPage+")", "logs_vaccess.log", false)
return false
}
return true
}
// Обработчик запросов
func handler(w http.ResponseWriter, r *http.Request) {
host := Alias_Run(r) // Получаем хост из запроса
https_check := !(r.TLS == nil) // Проверяем, по HTTPS ли запрос
root_url := r.URL.Path == "/" // Проверяем, является ли запрос корневым URL
// Проверяем, обработал ли прокси запрос
if StartHandlerProxy(w, r) {
return // Если прокси обработал запрос, прерываем выполнение
}
// ЕДИНСТВЕННАЯ ПРОВЕРКА vAccess - простая проверка запрошенного пути
if !checkVAccessAndHandle(w, r, r.URL.Path, host) {
return
}
if https_check {
tools.Logs_file(0, "HTTPS", "🔍 IP клиента: "+r.RemoteAddr+" Обработка запроса: https://"+r.Host+r.URL.Path, "logs_https.log", false)
} else {
tools.Logs_file(0, "HTTP", "🔍 IP клиента: "+r.RemoteAddr+" Обработка запроса: http://"+r.Host+r.URL.Path, "logs_http.log", false)
// Если сертификат для домена существует в папке cert, перенаправляем на HTTPS
if checkHostCert(r) {
// Если запрос не по HTTPS, перенаправляем на HTTPS
httpsURL := "https://" + r.Host + r.URL.RequestURI()
http.Redirect(w, r, httpsURL, http.StatusMovedPermanently)
return // Прерываем выполнение после редиректа
}
}
// Проверяем существование директории сайта
if _, err := os.Stat("WebServer/www/" + host + "/public_www"); err != nil {
http.ServeFile(w, r, "WebServer/tools/error_page/index.html")
tools.Logs_file(2, "H404", "🔍 IP клиента: "+r.RemoteAddr+" Директория сайта не найдена: "+host, "logs_http.log", false)
return
}
if root_url {
// Если корневой URL, то ищем первый существующий root файл
if rootFile, found := findExistingRootFile(host, "/"); found {
// Обрабатываем найденный root файл (статический или PHP)
HandlePHPRequest(w, r, host, "/"+rootFile, r.URL.RequestURI(), r.URL.Path)
} else {
// Ни один root файл не найден - показываем ошибку
rootFiles := getRootFiles(host)
tools.Logs_file(2, "H404", "🔍 IP клиента: "+r.RemoteAddr+" Root файлы не найдены: "+strings.Join(rootFiles, ", "), "logs_http.log", false)
http.ServeFile(w, r, "WebServer/tools/error_page/index.html")
}
}
if !root_url {
// Проверяем существование запрашиваемого файла
filePath := "WebServer/www/" + host + "/public_www" + r.URL.Path
if fileInfo, err := os.Stat(filePath); err == nil {
// Путь существует - проверяем что это
if fileInfo.IsDir() {
// Это директория - ищем индексные файлы
// Убираем слэш в конце если есть, и добавляем обратно для единообразия
dirPath := r.URL.Path
if !strings.HasSuffix(dirPath, "/") {
dirPath += "/"
}
// Ищем первый существующий root файл в директории
if rootFile, found := findExistingRootFile(host, dirPath); found {
// Обрабатываем найденный индексный файл в директории
HandlePHPRequest(w, r, host, dirPath+rootFile, r.URL.RequestURI(), r.URL.Path)
return
}
// Если никаких индексных файлов нет - показываем ошибку (запрещаем листинг)
rootFiles := getRootFiles(host)
tools.Logs_file(2, "H404", "🔍 IP клиента: "+r.RemoteAddr+" Индексные файлы не найдены в директории "+r.Host+r.URL.Path+": "+strings.Join(rootFiles, ", "), "logs_http.log", false)
http.ServeFile(w, r, "WebServer/tools/error_page/index.html")
} else {
// Это файл - обрабатываем через HandlePHPRequest
HandlePHPRequest(w, r, host, r.URL.Path, "", "")
}
} else {
// Файл не найден - проверяем нужен ли роутинг через root файл
if isRootFileRoutingEnabled(host) {
// Ищем первый существующий root файл для роутинга
if rootFile, found := findExistingRootFile(host, "/"); found {
// Root файл существует - используем для роутинга
HandlePHPRequest(w, r, host, "/"+rootFile, r.URL.RequestURI(), r.URL.Path)
} else {
// Root файлы не найдены
rootFiles := getRootFiles(host)
tools.Logs_file(2, "H404", "🔍 IP клиента: "+r.RemoteAddr+" Root файлы не найдены для роутинга: "+strings.Join(rootFiles, ", "), "logs_http.log", false)
http.ServeFile(w, r, "WebServer/tools/error_page/index.html")
}
} else {
// Роутинг отключен - показываем обычную 404
http.ServeFile(w, r, "WebServer/tools/error_page/index.html")
tools.Logs_file(2, "H404", "🔍 IP клиента: "+r.RemoteAddr+" Файл не найден: "+r.Host+r.URL.Path, "logs_http.log", false)
}
}
}
}