상세 컨텐츠

본문 제목

URL Tree <Path Tree> - 매칭

Language/..1

by yiaw 2021. 11. 5. 10:08

본문

앞선 포스팅에서는 Path Tree를 생성하는 코드를 소개했다. 

이제 실제 URL이 들어왔을 경우 해당 URL과 Path 가 일치하는지 확인하는 작업을 한다. 

 

먼저 Method 함수를 호출 한다.

func (t *Tree) MatchURL(method, path string) (bool, string, string) {
	var ok bool
	var npath string

	b := []byte(path)
	if b[0] == '/' {
		b = b[1:]
		npath = string(b)
	}

	newPath := npath + "/" + strings.ToUpper(method)

	p := strings.Split(newPath, "/")
	if len(p) > 1 {
		ok = matchurl(t.root, p)
	} else {
		ok = false
	}

	return ok, method, path
}

코드 내용을 간략하게 보자면 path (/api/v1/user .. 등)과 같이 실제 URL과 Method를 인자로 전달하여 Tree와 비교한다. 

각 URL Path를 String 배열에 저장 후 각 노드를 탐색하게 된다. 

 

내부적으로는 matchurl이라는 재귀 함수를 호출한다. 

 

func matchurl(node []Node, p []string) bool {
	var ok bool
	var i int

	for i = 0; i < len(node); i++ {
		if node[i].path[0] == '$' { // $ Method Field
			if node[i].path[1] == '*' || // * All Allowed Method
				node[i].path == p[0] { // Perfect Method Matching
				if len(p) > 1 {
					continue
				} else {
					ok = true

				}
				break
			}
		} else if node[i].path[0] == ':' || // : Dynamic Path
			node[i].path[0] == '*' {
			if len(p) > 1 {
				ok = true
			} else {
				continue
			}
			break
		} else if node[i].path == p[0] { // Perfect Path Matching
			ok = true
			break
		} else if node[i].path[0] != '*' && strings.Contains(node[i].path, "*") {
			// node path set '/user*'  match /username
			if ok, _ = regexp.MatchString(node[i].path, p[0]); !ok {
				continue
			} else {
				break
			}
		}
	}

	if i == len(node) {
		return false
	}

	if len(p) > 1 {
		if node[i].path == "*" {
			p = p[len(p)-2:]
		}
		ok = matchurl(node[i].child, p[1:])
	}

	return ok
}

for문 내부적으로 확인해보면 Node에 저장된 Path와 p[0]를 비교 시 Node에 저장된 "*" ":"를 보게 되는데 "*"는 뒤에 오는 모든 path를 허용이며 ":"는 동적 Path 일 경우 Depth만을 확인해준다. 또는 주석에  나와있는 거와 같이 user*처럼 저장된 노드에서는 user뒤 모든 strings를 통과시킨다. 

 

아래 node[i].path 가 "*" 일 경우에는 뒤 모든 Path를 통과 시킴으로 마지막에 저장된 Method만 확인하면 된다. 

p[len(p)-2:] 이 맨 마지막 배열로 이동시킨다. 이렇게 각 노드를 확인 후 실제 Match URL을 확인해보자 

 

 

package main

import (
	"fmt"
	"urltree"
)

func main() {
	utree := urltree.NewTree("auth")
	utree.Make("GET", "/api/v1/user/:username")
	utree.Make("POST", "/api/v1/user/:username")
	utree.Make("DELETE", "/api/v1/user/:username")
	utree.Make("PATCH", "/api/v1/user/:username")
	utree.Make("GET", "/api/v1/user")
	utree.Make("DELETE", "/api/v1/user")
	utree.Make("GET", "/api/v1/config")
	utree.Make("GET", "/api/v1/config/*")
	utree.Make("*", "/api/v1/alert/:alertname")
	utree.Make("GET", "/api/v1/alert/:alertname/*")
	utree.Printing()

	var Method = []string{"POST", "GET", "DELETE", "PATCH"}
	var InputURL = []string{
		"/api/v1/user",
		"/api/v1/user/yiaw",
		"/api/v1/alert/status",
		"/api/v1/alert/status/moduleinfo",
		"/api/v1/config",
		"/api/v1/config/setting",
	}

	for i := 0; i < len(InputURL); i++ {
		for j := 0; j < len(Method); j++ {
			ok, method, url := utree.MatchURL(Method[j], InputURL[i])
			fmt.Printf("Bool = %-15t Method = %-7s URL = %s\n", ok, method, url)
		}
	}
}

 

위 Make Method 생성시 아래와 같은 트리가 생성된다. 

 

auth
api
└── v1
    ├── user
    │   ├── :username
    │   │   ├── $GET
    │   │   ├── $POST
    │   │   ├── $DELETE
    │   │   └── $PATCH
    │   ├── $GET
    │   └── $DELETE
    ├── config
    │   ├── $GET
    │   └── *
    │       └── $GET
    └── alert
        └── :alertname
            ├── $*
            └── *
                └── $POST

 

Input URL과 Method 입력시 매칭되는 정보는 다음과 같다.

============== Matching 결과 =====================
Bool = false           Method = POST    URL = /api/v1/user
Bool = true            Method = GET     URL = /api/v1/user
Bool = true            Method = DELETE  URL = /api/v1/user
Bool = false           Method = PATCH   URL = /api/v1/user
Bool = true            Method = POST    URL = /api/v1/user/yiaw
Bool = true            Method = GET     URL = /api/v1/user/yiaw
Bool = true            Method = DELETE  URL = /api/v1/user/yiaw
Bool = true            Method = PATCH   URL = /api/v1/user/yiaw
Bool = true            Method = POST    URL = /api/v1/alert/status
Bool = true            Method = GET     URL = /api/v1/alert/status
Bool = true            Method = DELETE  URL = /api/v1/alert/status
Bool = true            Method = PATCH   URL = /api/v1/alert/status
Bool = false           Method = POST    URL = /api/v1/alert/status/moduleinfo
Bool = true            Method = GET     URL = /api/v1/alert/status/moduleinfo
Bool = false           Method = DELETE  URL = /api/v1/alert/status/moduleinfo
Bool = false           Method = PATCH   URL = /api/v1/alert/status/moduleinfo
Bool = false           Method = POST    URL = /api/v1/config
Bool = true            Method = GET     URL = /api/v1/config
Bool = false           Method = DELETE  URL = /api/v1/config
Bool = false           Method = PATCH   URL = /api/v1/config
Bool = false           Method = POST    URL = /api/v1/config/setting
Bool = true            Method = GET     URL = /api/v1/config/setting
Bool = false           Method = DELETE  URL = /api/v1/config/setting
Bool = false           Method = PATCH   URL = /api/v1/config/setting

 

'Language > ..1' 카테고리의 다른 글

URL Tree <Path Tree> - 생성  (0) 2021.11.05
Golang을 이용하여 Http Client - 세븐나이츠2 쿠폰 입력  (0) 2021.11.04

관련글 더보기

댓글 영역