Skip to content

Commit 7c0578f

Browse files
committed
refactor(serverHandler): parse URL query by url.Query()
For getting query values, previous solution is parsing raw query string manually to save memory. It's not so convenient when query parameter combinations increase. Changed to parsing by standard library method `url.Query`. BREAKING CHANGE `?simpledownload` is no more supported. Use `?simple&download` instead. Before: ``` GET /path?simpledownload ``` After: ``` GET /path?simple&download ```
1 parent 4bfc927 commit 7c0578f

File tree

9 files changed

+75
-90
lines changed

9 files changed

+75
-90
lines changed

src/serverHandler/aliasHandler.go

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -8,12 +8,14 @@ import (
88
"mjpclab.dev/ghfs/src/user"
99
"mjpclab.dev/ghfs/src/util"
1010
"net/http"
11+
"net/url"
1112
"regexp"
1213
"strconv"
1314
"strings"
1415
)
1516

1617
var defaultHandler = http.NotFoundHandler()
18+
var emptyUrlQuery = url.Values{}
1719

1820
type aliasHandler struct {
1921
alias
@@ -100,15 +102,16 @@ func (h *aliasHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
100102

101103
if session.authSuccess {
102104
if session.requestAuth {
103-
h.redirectWithoutRequestAuth(w, r, session, data)
105+
returnUrl := h.extractNoAuthUrl(r, session, data)
106+
http.Redirect(w, r, returnUrl, http.StatusFound)
104107
return
105108
}
106109

107110
if session.redirectAction == addSlashSuffix {
108-
redirect(w, r, session.prefixReqPath+"/", h.autoDirSlash)
111+
redirectWithQuery(w, r, session.prefixReqPath+"/", h.autoDirSlash)
109112
return
110113
} else if session.redirectAction == removeSlashSuffix {
111-
redirect(w, r, session.prefixReqPath[:len(session.prefixReqPath)-1], h.autoDirSlash)
114+
redirectWithQuery(w, r, session.prefixReqPath[:len(session.prefixReqPath)-1], h.autoDirSlash)
112115
return
113116
}
114117

src/serverHandler/archive.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -59,7 +59,7 @@ func (h *aliasHandler) visitTreeNode(
5959
break
6060
}
6161

62-
needAuth, _ := h.needAuth("", urlPath, fsPath)
62+
needAuth, _ := h.needAuth(emptyUrlQuery, urlPath, fsPath)
6363
userId, _, err := h.verifyAuth(r, urlPath, fsPath)
6464
if needAuth && err != nil {
6565
return

src/serverHandler/auth.go

Lines changed: 19 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -4,13 +4,12 @@ import (
44
"errors"
55
"net/http"
66
"net/url"
7-
"strings"
87
)
98

109
const authQueryParam = "auth"
1110

12-
func (h *aliasHandler) needAuth(rawQuery, vhostReqPath, reqFsPath string) (needAuth, requestAuth bool) {
13-
if strings.HasPrefix(rawQuery, authQueryParam) {
11+
func (h *aliasHandler) needAuth(query url.Values, vhostReqPath, reqFsPath string) (needAuth, requestAuth bool) {
12+
if query.Has(authQueryParam) {
1413
return true, true
1514
}
1615

@@ -55,25 +54,26 @@ func (h *aliasHandler) verifyAuth(r *http.Request, vhostReqPath, reqFsPath strin
5554
return
5655
}
5756

58-
func (h *aliasHandler) redirectWithoutRequestAuth(w http.ResponseWriter, r *http.Request, session *sessionContext, data *responseData) {
59-
var returnUrl string
60-
index := strings.Index(r.URL.RawQuery, authQueryParam+"=")
61-
if index >= 0 {
62-
returnUrl = r.URL.RawQuery[index+len(authQueryParam)+1:]
63-
index = strings.LastIndexByte(returnUrl, '&')
64-
if index >= 0 {
65-
returnUrl = returnUrl[:index]
57+
func (h *aliasHandler) extractNoAuthUrl(r *http.Request, session *sessionContext, data *responseData) string {
58+
if session.query.Has(authQueryParam) {
59+
returnUrl := session.query.Get(authQueryParam)
60+
61+
if len(returnUrl) > 0 {
62+
url, err := url.QueryUnescape(returnUrl)
63+
if err == nil {
64+
returnUrl = url
65+
}
6666
}
67-
url, err := url.QueryUnescape(returnUrl)
68-
if err == nil {
69-
returnUrl = url
67+
68+
if len(returnUrl) > 0 {
69+
return returnUrl
7070
}
71-
} else {
72-
returnUrl = r.Header.Get("Referer")
7371
}
74-
if len(returnUrl) == 0 {
75-
returnUrl = session.prefixReqPath + data.Context.QueryString()
72+
73+
referrer := r.Header.Get("Referer")
74+
if len(referrer) > 0 {
75+
return referrer
7676
}
7777

78-
http.Redirect(w, r, returnUrl, http.StatusFound)
78+
return session.prefixReqPath + data.Context.QueryString()
7979
}

src/serverHandler/pathContext.go

Lines changed: 5 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -8,16 +8,14 @@ type pathContext struct {
88
}
99

1010
func (ctx pathContext) QueryString() string {
11-
// ?simpledownload&sort=x/&
12-
buffer := make([]byte, 1, 24)
11+
// ?simple&download&sort=x/&
12+
buffer := make([]byte, 1, 25)
1313
buffer[0] = '?' // 1 byte
1414

15-
switch {
16-
case ctx.simple && ctx.download:
17-
buffer = append(buffer, []byte("simpledownload&")...) // 15 bytes
18-
case ctx.simple:
15+
if ctx.simple {
1916
buffer = append(buffer, []byte("simple&")...) // 7 bytes
20-
case ctx.download:
17+
}
18+
if ctx.download {
2119
buffer = append(buffer, []byte("download&")...) // 9 bytes
2220
}
2321

src/serverHandler/pathContext_test.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -53,7 +53,7 @@ func TestPathContext(t *testing.T) {
5353
}
5454

5555
result = (&pathContext{simple: true, download: true}).QueryString()
56-
if result != "?simpledownload" {
56+
if result != "?simple&download" {
5757
t.Error(result)
5858
}
5959

@@ -77,7 +77,7 @@ func TestPathContext(t *testing.T) {
7777

7878
sort = "/n"
7979
result = (&pathContext{simple: true, download: true, sort: &sort}).QueryString()
80-
if result != "?simpledownload&sort=/n" {
80+
if result != "?simple&download&sort=/n" {
8181
t.Error(result)
8282
}
8383
}

src/serverHandler/redirect.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ package serverHandler
22

33
import "net/http"
44

5-
func redirect(w http.ResponseWriter, r *http.Request, path string, code int) {
5+
func redirectWithQuery(w http.ResponseWriter, r *http.Request, path string, code int) {
66
target := path
77
if len(r.URL.RawQuery) > 0 {
88
target += "?" + r.URL.RawQuery

src/serverHandler/sessionData.go

Lines changed: 26 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ import (
66
"mjpclab.dev/ghfs/src/i18n"
77
"mjpclab.dev/ghfs/src/util"
88
"net/http"
9+
"net/url"
910
"os"
1011
"path"
1112
"path/filepath"
@@ -81,6 +82,8 @@ type sessionContext struct {
8182

8283
file *os.File
8384

85+
query url.Values
86+
8487
errors []error
8588
}
8689

@@ -355,11 +358,11 @@ func (h *aliasHandler) getSessionData(r *http.Request) (session *sessionContext,
355358
reqPath := util.CleanUrlPath(vhostReqPath[len(h.url):])
356359
fsPath := filepath.Clean(h.dir + reqPath)
357360

358-
rawQuery := r.URL.RawQuery
361+
query := r.URL.Query()
359362

360363
status := http.StatusOK
361364

362-
needAuth, requestAuth := h.needAuth(rawQuery, vhostReqPath, fsPath)
365+
needAuth, requestAuth := h.needAuth(query, vhostReqPath, fsPath)
363366
authUserId, authUserName, _authErr := h.verifyAuth(r, vhostReqPath, fsPath)
364367
authSuccess := !needAuth || _authErr == nil
365368
if !authSuccess {
@@ -369,47 +372,39 @@ func (h *aliasHandler) getSessionData(r *http.Request) (session *sessionContext,
369372

370373
headers := h.getHeaders(vhostReqPath, fsPath, authSuccess)
371374

372-
isSimple := false
373-
isDownload := false
375+
isMutate := false
374376
isUpload := false
375377
isMkdir := false
376378
isDelete := false
377-
isMutate := false
378379
switch {
379-
case strings.HasPrefix(rawQuery, "simpledownload"):
380-
isSimple = true
381-
isDownload = true
382-
case strings.HasPrefix(rawQuery, "simple"):
383-
isSimple = true
384-
case strings.HasPrefix(rawQuery, "download"):
385-
isDownload = true
386-
case strings.HasPrefix(rawQuery, "upload") && r.Method == http.MethodPost:
380+
case query.Has("upload"):
381+
isMutate = true
387382
isUpload = true
383+
case query.Has("mkdir"):
388384
isMutate = true
389-
case strings.HasPrefix(rawQuery, "mkdir"):
390385
isMkdir = true
386+
case query.Has("delete"):
391387
isMutate = true
392-
case strings.HasPrefix(r.URL.RawQuery, "delete"):
393388
isDelete = true
394-
isMutate = true
395389
}
396390

397391
isArchive := false
398392
var arFmt archiveFormat
399-
if len(rawQuery) == 3 || (len(rawQuery) > 3 && rawQuery[3] == '&') {
400-
switch rawQuery[:3] {
401-
case "tar":
402-
isArchive = true
403-
arFmt = tarFmt
404-
case "tgz":
405-
isArchive = true
406-
arFmt = tgzFmt
407-
case "zip":
408-
isArchive = true
409-
arFmt = zipFmt
410-
}
393+
switch {
394+
case query.Has("tar"):
395+
isArchive = true
396+
arFmt = tarFmt
397+
case query.Has("tgz"):
398+
isArchive = true
399+
arFmt = tgzFmt
400+
case query.Has("zip"):
401+
isArchive = true
402+
arFmt = zipFmt
411403
}
412404

405+
isSimple := query.Has("simple")
406+
isDownload := query.Has("download")
407+
413408
accepts := acceptHeaders.ParseAccepts(r.Header.Get("Accept"))
414409
acceptIndex, _, _ := accepts.GetPreferredValue(acceptContentTypes)
415410
wantJson := acceptIndex == acceptJsonIndex
@@ -489,7 +484,7 @@ func (h *aliasHandler) getSessionData(r *http.Request) (session *sessionContext,
489484
}
490485

491486
subItems = h.FilterItems(subItems)
492-
rawSortBy, sortState := sortInfos(subItems, rawQuery, h.defaultSort)
487+
rawSortBy, sortState := sortInfos(subItems, query.Get("sort"), h.defaultSort)
493488

494489
if h.emptyRoot && status == http.StatusOK && len(vhostReqPath) > 1 {
495490
status = http.StatusNotFound
@@ -535,6 +530,8 @@ func (h *aliasHandler) getSessionData(r *http.Request) (session *sessionContext,
535530

536531
file: file,
537532

533+
query: query,
534+
538535
errors: errs,
539536
}
540537
data = &responseData{

src/serverHandler/sort.go

Lines changed: 2 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,6 @@ import (
55
"mjpclab.dev/ghfs/src/util"
66
"os"
77
"sort"
8-
"strings"
98
)
109

1110
// compare dir func
@@ -358,22 +357,10 @@ func sortInfoOriginal(items []os.FileInfo, compareDir fnCompareDir) {
358357

359358
// sort
360359

361-
func sortInfos(items []os.FileInfo, rawQuery string, defaultSortBy string) (rawSortBy *string, sortInfo SortState) {
362-
const sortPrefix = "sort="
363-
var sortBy string
364-
365-
// extract sort string
366-
iSortBy := strings.Index(rawQuery, sortPrefix)
367-
if iSortBy < 0 {
360+
func sortInfos(items []os.FileInfo, sortBy string, defaultSortBy string) (rawSortBy *string, sortInfo SortState) {
361+
if len(sortBy) == 0 {
368362
sortBy = defaultSortBy
369363
} else {
370-
if len(rawQuery) > iSortBy+len(sortPrefix) {
371-
sortBy = rawQuery[iSortBy+len(sortPrefix):]
372-
iAmp := strings.IndexByte(sortBy, '&')
373-
if iAmp >= 0 {
374-
sortBy = sortBy[:iAmp]
375-
}
376-
}
377364
rawSortBy = &sortBy
378365
}
379366

0 commit comments

Comments
 (0)