Rework HTTP request handling entirely
Some checks are pending
Build CI / build (push) Waiting to run
golangci-lint / lint (push) Waiting to run

This commit is contained in:
Palapeli
2026-04-06 11:35:02 -04:00
parent 9a1e0a21cf
commit c002bb81a6
12 changed files with 266 additions and 292 deletions

View File

@@ -1,6 +1,7 @@
package api
import (
"net/http"
"wwfc/common"
"wwfc/database"
)
@@ -30,3 +31,11 @@ func StartServer(reload bool) {
func Shutdown() {
db.Close()
}
func RegisterHandlers(mux *http.ServeMux) {
mux.HandleFunc("/api/groups", HandleGroups)
mux.HandleFunc("/api/stats", HandleStats)
mux.HandleFunc("/api/ban", HandleBan)
mux.HandleFunc("/api/unban", HandleUnban)
mux.HandleFunc("/api/kick", HandleKick)
}

View File

@@ -23,7 +23,9 @@ var (
dlcDir = "./dlc"
)
func handleAuthRequest(moduleName string, w http.ResponseWriter, r *http.Request) {
func handleAuthRequest(w http.ResponseWriter, r *http.Request) {
moduleName := getModuleName(r)
err := r.ParseForm()
if err != nil {
logging.Error(moduleName, "Failed to parse form")
@@ -88,7 +90,8 @@ func handleAuthRequest(moduleName string, w http.ResponseWriter, r *http.Request
reply := map[string]string{}
var response []byte
if r.URL.String() == "/ac" {
switch r.URL.String() {
case "/ac":
action, ok := fields["action"]
if !ok || action == "" {
logging.Error(moduleName, "No action in form")
@@ -114,7 +117,8 @@ func handleAuthRequest(moduleName string, w http.ResponseWriter, r *http.Request
"returncd": "109",
}
}
} else if r.URL.String() == "/pr" {
case "/pr":
words, ok := fields["words"]
if words == "" || !ok {
logging.Error(moduleName, "No words in form")
@@ -123,7 +127,8 @@ func handleAuthRequest(moduleName string, w http.ResponseWriter, r *http.Request
}
reply = handleProfanity(r.PostForm, unitcd)
} else if r.URL.String() == "/download" {
case "/download":
action, ok := fields["action"]
if !ok || action == "" {
logging.Error(moduleName, "No action in form")

View File

@@ -5,7 +5,7 @@ import (
"strconv"
)
func handleConnectionTest(w http.ResponseWriter) {
func handleConnectionTest(w http.ResponseWriter, r *http.Request) {
response := "\n"
response += ` <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">` + "\n"
response += ` <html>` + "\n"

93
nas/listener.go Normal file
View File

@@ -0,0 +1,93 @@
package nas
import (
"bufio"
"bytes"
"errors"
"io"
"net"
"net/http"
"strings"
"wwfc/common"
"wwfc/logging"
"github.com/logrusorgru/aurora/v3"
)
type nasListener struct {
net.Listener
}
type nasConn struct {
net.Conn
reader io.Reader
}
func (l *nasListener) Accept() (net.Conn, error) {
conn, err := l.Listener.Accept()
if err != nil {
return nil, err
}
return &nasConn{
Conn: conn,
reader: filterDuplicateHost(conn),
}, nil
}
func (c *nasConn) Read(b []byte) (int, error) {
return c.reader.Read(b)
}
// filterDuplicateHost wraps a net.Conn and filters out duplicate Host headers from the HTTP request,
// making the invalid requests sent by DWC acceptable to the standard library's HTTP server.
func filterDuplicateHost(c net.Conn) io.Reader {
r := bufio.NewReader(c)
// Read the first line of the HTTP request
line, err := r.ReadString('\n')
if err != nil {
return io.MultiReader(strings.NewReader(line), r)
}
// Is this an HTTP request?
if !strings.HasSuffix(line, "HTTP/1.1\r\n") {
return io.MultiReader(strings.NewReader(line), r)
}
// Iterate through the HTTP headers and remove any duplicate Host headers
var headers bytes.Buffer
hostSeen := false
for {
headerLine, err := r.ReadString('\n')
if err != nil || headerLine == "\r\n" {
headers.WriteString(headerLine)
break
}
if strings.HasPrefix(strings.ToLower(headerLine), "host:") {
if hostSeen {
continue
}
hostSeen = true
}
headers.WriteString(headerLine)
}
return io.MultiReader(strings.NewReader(line+headers.String()), r)
}
func listenAndServe(address string) {
logging.Notice("NAS", "Starting HTTP server on", aurora.BrightCyan(address))
l, err := net.Listen("tcp", address)
common.ShouldNotError(err)
listener := &nasListener{Listener: l}
defer func() {
common.ShouldNotError(listener.Close())
}()
err = server.Serve(listener)
if err != nil && !errors.Is(err, http.ErrServerClosed) {
panic(err)
}
}

View File

@@ -1,16 +1,10 @@
package nas
import (
"bufio"
"bytes"
"context"
"errors"
"io"
"net"
"net/http"
"regexp"
"strconv"
"strings"
"time"
"wwfc/api"
"wwfc/common"
@@ -28,23 +22,18 @@ var (
payloadServerAddress string
)
type nasListener struct {
net.Listener
}
type nasConn struct {
net.Conn
reader io.Reader
}
var (
authMux = http.NewServeMux()
sakeMux = http.NewServeMux()
gamestatsMux = http.NewServeMux()
raceMux = http.NewServeMux()
)
func StartServer(reload bool) {
// Get config
config := common.GetConfig()
serverName = config.ServerName
address := *config.NASAddress + ":" + config.NASPort
payloadServerAddress = config.PayloadServerAddress
if config.EnableHTTPS {
@@ -63,22 +52,36 @@ func StartServer(reload bool) {
ReadTimeout: 10 * time.Second,
}
logging.Notice("NAS", "Starting HTTP server on", aurora.BrightCyan(address))
authMux.HandleFunc("/ac", handleAuthRequest)
authMux.HandleFunc("/pr", handleAuthRequest)
authMux.HandleFunc("/download", handleAuthRequest)
l, err := net.Listen("tcp", address)
common.ShouldNotError(err)
listener := &nasListener{Listener: l}
if payloadServerAddress != "" {
// Forward the request to the payload server
authMux.HandleFunc("/payload", forwardPayloadRequest)
} else {
authMux.HandleFunc("/payload", handlePayloadRequest)
}
go func(l net.Listener) {
defer func() {
common.ShouldNotError(listener.Close())
}()
for i := 0; i <= 9; i++ {
authMux.HandleFunc("/w"+strconv.Itoa(i), downloadStage1)
}
err := server.Serve(listener)
if err != nil && !errors.Is(err, http.ErrServerClosed) {
panic(err)
}
}(listener)
authMux.HandleFunc("/nastest.jsp", handleNASTest)
http.HandleFunc("GET conntest.nintendowifi.net/", handleConnectionTest)
api.RegisterHandlers(http.DefaultServeMux)
sake.RegisterHandlers(sakeMux)
race.RegisterHandlers(raceMux)
gamestatsMux.HandleFunc("/", gamestats.HandleWebRequest)
http.HandleFunc("/", handleUnknown)
authMux.HandleFunc("/", handleUnknown)
sakeMux.HandleFunc("/", handleUnknown)
raceMux.HandleFunc("/", handleUnknown)
go listenAndServe(address)
}
func Shutdown() {
@@ -95,161 +98,27 @@ func Shutdown() {
}
}
func (l *nasListener) Accept() (net.Conn, error) {
conn, err := l.Listener.Accept()
if err != nil {
return nil, err
}
return &nasConn{
Conn: conn,
reader: filterDuplicateHost(conn),
}, nil
var hostMuxes = map[*regexp.Regexp]*http.ServeMux{
regexp.MustCompile(`^(nas|naswii|dls1)\.`): authMux,
regexp.MustCompile(`(\.|^)gamestats2?\.(gs\.|gamespy\.com$)`): gamestatsMux,
regexp.MustCompile(`(\.|^)sake\.(gs\.|gamespy\.com$)`): sakeMux,
regexp.MustCompile(`(\.|^)race\.(gs\.|gamespy\.com$)`): raceMux,
}
func (c *nasConn) Read(b []byte) (int, error) {
return c.reader.Read(b)
}
// filterDuplicateHost wraps a net.Conn and filters out duplicate Host headers from the HTTP request,
// making the invalid requests sent by DWC acceptable to the standard library's HTTP server.
func filterDuplicateHost(c net.Conn) io.Reader {
r := bufio.NewReader(c)
// Read the first line of the HTTP request
line, err := r.ReadString('\n')
if err != nil {
return io.MultiReader(strings.NewReader(line), r)
}
// Is this an HTTP request?
if !strings.HasSuffix(line, "HTTP/1.1\r\n") {
return io.MultiReader(strings.NewReader(line), r)
}
// Iterate through the HTTP headers and remove any duplicate Host headers
var headers bytes.Buffer
hostSeen := false
for {
headerLine, err := r.ReadString('\n')
if err != nil || headerLine == "\r\n" {
headers.WriteString(headerLine)
break
}
if strings.HasPrefix(strings.ToLower(headerLine), "host:") {
if hostSeen {
continue
}
hostSeen = true
}
headers.WriteString(headerLine)
}
return io.MultiReader(strings.NewReader(line+headers.String()), r)
}
var regexRaceHost = regexp.MustCompile(`(\.|^)race\.(gs\.|gamespy\.com$)`)
var regexSakeHost = regexp.MustCompile(`(\.|^)sake\.(gs\.|gamespy\.com$)`)
var regexGamestatsHost = regexp.MustCompile(`(\.|^)gamestats2?\.(gs\.|gamespy\.com$)`)
var regexStage1URL = regexp.MustCompile(`^/w([0-9])$`)
func handleRequest(w http.ResponseWriter, r *http.Request) {
// Check for *.sake.gs.* or sake.gs.*
if regexSakeHost.MatchString(r.Host) {
// Redirect to the sake server
sake.HandleRequest(w, r)
return
}
// Check for *.gamestats(2).gs.* or gamestats(2).gs.*
if regexGamestatsHost.MatchString(r.Host) {
// Redirect to the gamestats server
gamestats.HandleWebRequest(w, r)
return
}
// Check for *.race.gs.* or race.gs.*
if regexRaceHost.MatchString(r.Host) {
// Redirect to the race server
race.HandleRequest(w, r)
return
}
moduleName := "NAS:" + r.RemoteAddr
// Handle conntest server
if strings.HasPrefix(r.Host, "conntest.") {
handleConnectionTest(w)
return
}
// Handle DWC auth requests
if r.URL.String() == "/ac" || r.URL.String() == "/pr" || r.URL.String() == "/download" {
handleAuthRequest(moduleName, w, r)
return
}
// Handle /nastest.jsp
if r.URL.Path == "/nastest.jsp" {
handleNASTest(w)
return
}
// Check for /payload
if strings.HasPrefix(r.URL.String(), "/payload") {
logging.Info("NAS", aurora.Yellow(r.Method), aurora.Cyan(r.URL), "via", aurora.Cyan(r.Host), "from", aurora.BrightCyan(r.RemoteAddr))
if payloadServerAddress != "" {
// Forward the request to the payload server
forwardPayloadRequest(moduleName, w, r)
} else {
handlePayloadRequest(moduleName, w, r)
// Check for host-specific muxes
for regex, mux := range hostMuxes {
if regex.MatchString(r.Host) {
mux.ServeHTTP(w, r)
return
}
return
}
// Stage 1
if match := regexStage1URL.FindStringSubmatch(r.URL.String()); match != nil {
val, err := strconv.Atoi(match[1])
if err != nil {
panic(err)
}
http.DefaultServeMux.ServeHTTP(w, r)
}
logging.Info("NAS", "Get stage 1:", aurora.Yellow(r.Method), aurora.Cyan(r.URL), "via", aurora.Cyan(r.Host), "from", aurora.BrightCyan(r.RemoteAddr))
downloadStage1(w, val)
return
}
// Check for /api/groups
if r.URL.Path == "/api/groups" {
api.HandleGroups(w, r)
return
}
// Check for /api/stats
if r.URL.Path == "/api/stats" {
api.HandleStats(w, r)
return
}
// Check for /api/ban
if r.URL.Path == "/api/ban" {
api.HandleBan(w, r)
return
}
// Check for /api/unban
if r.URL.Path == "/api/unban" {
api.HandleUnban(w, r)
return
}
// Check for /api/kick
if r.URL.Path == "/api/kick" {
api.HandleKick(w, r)
return
}
logging.Info("NAS", aurora.Yellow(r.Method), aurora.Cyan(r.URL), "via", aurora.Cyan(r.Host), "from", aurora.BrightCyan(r.RemoteAddr))
replyHTTPError(w, 404, "404 Not Found")
func getModuleName(r *http.Request) string {
return "NAS:" + r.RemoteAddr
}
func replyHTTPError(w http.ResponseWriter, errorCode int, errorString string) {
@@ -269,7 +138,12 @@ func replyHTTPError(w http.ResponseWriter, errorCode int, errorString string) {
_, _ = w.Write([]byte(response))
}
func handleNASTest(w http.ResponseWriter) {
func handleUnknown(w http.ResponseWriter, r *http.Request) {
logging.Info(getModuleName(r), "Unknown request:", aurora.Yellow(r.Method), aurora.Cyan(r.Host+r.URL.Path))
replyHTTPError(w, http.StatusNotFound, "404 Not Found")
}
func handleNASTest(w http.ResponseWriter, r *http.Request) {
response := "" +
"<html>\n" +
"<body>\n" +
@@ -287,44 +161,3 @@ func handleNASTest(w http.ResponseWriter) {
w.WriteHeader(200)
_, _ = w.Write([]byte(response))
}
func forwardPayloadRequest(moduleName string, w http.ResponseWriter, r *http.Request) {
client := &http.Client{
Timeout: 10 * time.Second,
}
r.URL.Scheme = "http"
r.URL.Host = payloadServerAddress
r.RequestURI = ""
r.Host = payloadServerAddress
resp, err := client.Do(r)
if err != nil {
logging.Error(moduleName, "Error forwarding payload request:", err)
replyHTTPError(w, http.StatusBadGateway, "502 Bad Gateway")
return
}
defer func() {
_ = resp.Body.Close()
}()
// Copy the response headers and status code
for key, values := range resp.Header {
for _, value := range values {
w.Header().Add(key, value)
}
}
w.WriteHeader(resp.StatusCode)
// Copy the response body
body, err := io.ReadAll(resp.Body)
if err != nil {
logging.Error(moduleName, "Error reading payload response body:", err)
replyHTTPError(w, http.StatusInternalServerError, "500 Internal Server Error")
return
}
_, err = w.Write(body)
if err != nil {
logging.Error(moduleName, "Error writing payload response body:", err)
}
}

View File

@@ -9,19 +9,23 @@ import (
"crypto/x509"
"encoding/hex"
"encoding/pem"
"io"
"net/http"
"net/url"
"os"
"strconv"
"time"
"wwfc/logging"
"github.com/logrusorgru/aurora/v3"
)
func downloadStage1(w http.ResponseWriter, stage1Ver int) {
func downloadStage1(w http.ResponseWriter, r *http.Request) {
stage1Ver := r.URL.Path[len(r.URL.Path)-1] - '0'
path := "payload/stage1.bin"
if stage1Ver != 0 {
path = "payload/stage1v" + strconv.Itoa(stage1Ver) + ".bin"
path = "payload/stage1v" + strconv.Itoa(int(stage1Ver)) + ".bin"
}
dat, err := os.ReadFile(path)
if err != nil {
@@ -38,10 +42,55 @@ func downloadStage1(w http.ResponseWriter, stage1Ver int) {
}
}
func handlePayloadRequest(moduleName string, w http.ResponseWriter, r *http.Request) {
func forwardPayloadRequest(w http.ResponseWriter, r *http.Request) {
moduleName := getModuleName(r)
client := &http.Client{
Timeout: 10 * time.Second,
}
r.URL.Scheme = "http"
r.URL.Host = payloadServerAddress
r.RequestURI = ""
r.Host = payloadServerAddress
resp, err := client.Do(r)
if err != nil {
logging.Error(moduleName, "Error forwarding payload request:", err)
replyHTTPError(w, http.StatusBadGateway, "502 Bad Gateway")
return
}
defer func() {
_ = resp.Body.Close()
}()
// Copy the response headers and status code
for key, values := range resp.Header {
for _, value := range values {
w.Header().Add(key, value)
}
}
w.WriteHeader(resp.StatusCode)
// Copy the response body
body, err := io.ReadAll(resp.Body)
if err != nil {
logging.Error(moduleName, "Error reading payload response body:", err)
replyHTTPError(w, http.StatusInternalServerError, "500 Internal Server Error")
return
}
_, err = w.Write(body)
if err != nil {
logging.Error(moduleName, "Error writing payload response body:", err)
}
}
func handlePayloadRequest(w http.ResponseWriter, r *http.Request) {
// Example request:
// GET /payload?g=RMCPD00&s=4e44b095817f8cfb62e6cffd57e9cfd411004a492784039ea4b2b7ca64717c91&h=9fdb6f60
moduleName := getModuleName(r)
u, err := url.Parse(r.URL.String())
if err != nil {
logging.Error(moduleName, "Failed to parse URL")

View File

@@ -2,12 +2,8 @@ package race
import (
"net/http"
"strings"
"wwfc/common"
"wwfc/database"
"wwfc/logging"
"github.com/logrusorgru/aurora/v3"
)
var (
@@ -28,12 +24,6 @@ func Shutdown() {
db.Close()
}
func HandleRequest(responseWriter http.ResponseWriter, request *http.Request) {
logging.Info("RACE", aurora.Yellow(request.Method), aurora.Cyan(request.URL), "via", aurora.Cyan(request.Host), "from", aurora.BrightCyan(request.RemoteAddr))
switch {
case strings.HasSuffix(request.URL.Path, "NintendoRacingService.asmx"):
moduleName := "RACE:RacingService:" + request.RemoteAddr
handleNintendoRacingServiceRequest(moduleName, responseWriter, request)
}
func RegisterHandlers(mux *http.ServeMux) {
mux.HandleFunc("POST /RaceService/NintendoRacingService.asmx", handleNintendoRacingServiceRequest)
}

View File

@@ -72,30 +72,32 @@ const (
xmlNamespace = "http://gamespy.net/RaceService/"
)
var marioKartWiiGameID = common.GetGameIDOrPanic("mariokartwii") // 1687
var marioKartWiiGameID = 1687
func handleNintendoRacingServiceRequest(moduleName string, responseWriter http.ResponseWriter, request *http.Request) {
soapActionHeader := request.Header.Get("SOAPAction")
func handleNintendoRacingServiceRequest(w http.ResponseWriter, r *http.Request) {
moduleName := "RACE:RacingService:" + r.RemoteAddr
soapActionHeader := r.Header.Get("SOAPAction")
if soapActionHeader == "" {
logging.Error(moduleName, "No SOAPAction header")
writeErrorResponse(raceServiceResultParseError, responseWriter)
writeErrorResponse(raceServiceResultParseError, w)
return
}
slashIndex := strings.LastIndex(soapActionHeader, "/")
if slashIndex == -1 {
logging.Error(moduleName, "Invalid SOAPAction header")
writeErrorResponse(raceServiceResultParseError, responseWriter)
writeErrorResponse(raceServiceResultParseError, w)
return
}
quotationMarkIndex := strings.Index(soapActionHeader[slashIndex+1:], "\"")
if quotationMarkIndex == -1 {
logging.Error(moduleName, "Invalid SOAPAction header")
writeErrorResponse(raceServiceResultParseError, responseWriter)
writeErrorResponse(raceServiceResultParseError, w)
return
}
requestBody, err := io.ReadAll(request.Body)
requestBody, err := io.ReadAll(r.Body)
if err != nil {
panic(err)
}
@@ -103,7 +105,7 @@ func handleNintendoRacingServiceRequest(moduleName string, responseWriter http.R
soapAction := soapActionHeader[slashIndex+1 : slashIndex+1+quotationMarkIndex]
switch soapAction {
case "GetTopTenRankings":
handleGetTopTenRankingsRequest(moduleName, responseWriter, requestBody)
handleGetTopTenRankingsRequest(moduleName, w, requestBody)
// TODO SubmitScores
default:

View File

@@ -24,32 +24,40 @@ var fileUploadHandlers = map[int]func(string, http.ResponseWriter, *http.Request
common.GetGameIDOrPanic("mariokartwii"): handleMarioKartWiiFileUploadRequest,
}
func handleFileRequest(moduleName string, responseWriter http.ResponseWriter, request *http.Request,
fileRequest FileRequest) {
func handleFileDownloadRequest(w http.ResponseWriter, r *http.Request) {
moduleName := "SAKE:File:" + r.RemoteAddr
gameIdString := request.URL.Query().Get("gameid")
gameIdString := r.URL.Query().Get("gameid")
gameId, err := strconv.Atoi(gameIdString)
if err != nil {
logging.Error(moduleName, "Invalid GameSpy game id")
return
}
var handler func(string, http.ResponseWriter, *http.Request)
var handlerExists bool
switch fileRequest {
case FileRequestDownload:
handler, handlerExists = fileDownloadHandlers[gameId]
case FileRequestUpload:
handler, handlerExists = fileUploadHandlers[gameId]
default:
logging.Error(moduleName, "Invalid file request")
logging.Error(moduleName, "Invalid GameSpy game ID:", aurora.Cyan(gameIdString))
return
}
handler, handlerExists := fileDownloadHandlers[gameId]
if !handlerExists {
logging.Warn(moduleName, "Unhandled file request for GameSpy game id:", aurora.Cyan(gameId))
logging.Warn(moduleName, "Unhandled file download request for GameSpy game ID:", aurora.Cyan(gameId))
return
}
handler(moduleName, responseWriter, request)
handler(moduleName, w, r)
}
func handleFileUploadRequest(w http.ResponseWriter, r *http.Request) {
moduleName := "SAKE:File:" + r.RemoteAddr
gameIdString := r.URL.Query().Get("gameid")
gameId, err := strconv.Atoi(gameIdString)
if err != nil {
logging.Error(moduleName, "Invalid GameSpy game ID:", aurora.Cyan(gameIdString))
return
}
handler, handlerExists := fileUploadHandlers[gameId]
if !handlerExists {
logging.Warn(moduleName, "Unhandled file upload request for GameSpy game ID:", aurora.Cyan(gameId))
return
}
handler(moduleName, w, r)
}

View File

@@ -2,12 +2,8 @@ package sake
import (
"net/http"
"strings"
"wwfc/common"
"wwfc/database"
"wwfc/logging"
"github.com/logrusorgru/aurora/v3"
)
var (
@@ -28,19 +24,9 @@ func Shutdown() {
db.Close()
}
func HandleRequest(w http.ResponseWriter, r *http.Request) {
logging.Info("SAKE", aurora.Yellow(r.Method), aurora.Cyan(r.URL), "via", aurora.Cyan(r.Host), "from", aurora.BrightCyan(r.RemoteAddr))
urlPath := r.URL.Path
switch {
case urlPath == "/SakeStorageServer/StorageServer.asmx":
moduleName := "SAKE:Storage:" + r.RemoteAddr
handleStorageRequest(moduleName, w, r)
case strings.HasSuffix(urlPath, "download.aspx"):
moduleName := "SAKE:File:" + r.RemoteAddr
handleFileRequest(moduleName, w, r, FileRequestDownload)
case strings.HasSuffix(urlPath, "upload.aspx"):
moduleName := "SAKE:File:" + r.RemoteAddr
handleFileRequest(moduleName, w, r, FileRequestUpload)
}
func RegisterHandlers(mux *http.ServeMux) {
mux.HandleFunc("POST /SakeStorageServer/StorageServer.asmx", handleStorageRequest)
mux.HandleFunc("GET /SakeFileServer/download.aspx", handleFileDownloadRequest)
mux.HandleFunc("POST /SakeFileServer/upload.aspx", handleFileUploadRequest)
mux.HandleFunc("GET /SakeFileServer/ghostdownload.aspx", handleMarioKartWiiGhostDownloadRequest)
}

View File

@@ -176,11 +176,6 @@ func getMarioKartWiiStoredGhostDataRecord(moduleName string, request StorageRequ
}
func handleMarioKartWiiFileDownloadRequest(moduleName string, responseWriter http.ResponseWriter, request *http.Request) {
if strings.HasSuffix(request.URL.Path, "ghostdownload.aspx") {
handleMarioKartWiiGhostDownloadRequest(moduleName, responseWriter, request)
return
}
query := request.URL.Query()
fileIdString := query.Get("fileid")
@@ -214,7 +209,9 @@ func handleMarioKartWiiFileDownloadRequest(moduleName string, responseWriter htt
}
}
func handleMarioKartWiiGhostDownloadRequest(moduleName string, responseWriter http.ResponseWriter, request *http.Request) {
func handleMarioKartWiiGhostDownloadRequest(responseWriter http.ResponseWriter, request *http.Request) {
moduleName := "SAKE:File:GhostDownload:" + request.RemoteAddr
query := request.URL.Query()
regionIdString := query.Get("region")

View File

@@ -175,7 +175,9 @@ var (
}
)
func handleStorageRequest(moduleName string, w http.ResponseWriter, r *http.Request) {
func handleStorageRequest(w http.ResponseWriter, r *http.Request) {
moduleName := "SAKE:Storage:" + r.RemoteAddr
headerAction := r.Header.Get("SOAPAction")
if headerAction == "" {
logging.Error(moduleName, "No SOAPAction in header")