endpoints.go 4.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180
  1. package dynamicproxy
  2. import (
  3. "encoding/json"
  4. "errors"
  5. "strings"
  6. "golang.org/x/text/cases"
  7. "golang.org/x/text/language"
  8. )
  9. /*
  10. endpoint.go
  11. author: tobychui
  12. This script handle the proxy endpoint object actions
  13. so proxyEndpoint can be handled like a proper oop object
  14. Most of the functions are implemented in dynamicproxy.go
  15. */
  16. /*
  17. User Defined Header Functions
  18. */
  19. // Check if a user define header exists in this endpoint, ignore case
  20. func (ep *ProxyEndpoint) UserDefinedHeaderExists(key string) bool {
  21. for _, header := range ep.UserDefinedHeaders {
  22. if strings.EqualFold(header.Key, key) {
  23. return true
  24. }
  25. }
  26. return false
  27. }
  28. // Remvoe a user defined header from the list
  29. func (ep *ProxyEndpoint) RemoveUserDefinedHeader(key string) error {
  30. newHeaderList := []*UserDefinedHeader{}
  31. for _, header := range ep.UserDefinedHeaders {
  32. if !strings.EqualFold(header.Key, key) {
  33. newHeaderList = append(newHeaderList, header)
  34. }
  35. }
  36. ep.UserDefinedHeaders = newHeaderList
  37. return nil
  38. }
  39. // Add a user defined header to the list, duplicates will be automatically removed
  40. func (ep *ProxyEndpoint) AddUserDefinedHeader(newHeaderRule *UserDefinedHeader) error {
  41. if ep.UserDefinedHeaderExists(newHeaderRule.Key) {
  42. ep.RemoveUserDefinedHeader(newHeaderRule.Key)
  43. }
  44. newHeaderRule.Key = cases.Title(language.Und, cases.NoLower).String(newHeaderRule.Key)
  45. ep.UserDefinedHeaders = append(ep.UserDefinedHeaders, newHeaderRule)
  46. return nil
  47. }
  48. /*
  49. Virtual Directory Functions
  50. */
  51. // Get virtual directory handler from given URI
  52. func (ep *ProxyEndpoint) GetVirtualDirectoryHandlerFromRequestURI(requestURI string) *VirtualDirectoryEndpoint {
  53. for _, vdir := range ep.VirtualDirectories {
  54. if strings.HasPrefix(requestURI, vdir.MatchingPath) {
  55. thisVdir := vdir
  56. return thisVdir
  57. }
  58. }
  59. return nil
  60. }
  61. // Get virtual directory handler by matching path (exact match required)
  62. func (ep *ProxyEndpoint) GetVirtualDirectoryRuleByMatchingPath(matchingPath string) *VirtualDirectoryEndpoint {
  63. for _, vdir := range ep.VirtualDirectories {
  64. if vdir.MatchingPath == matchingPath {
  65. thisVdir := vdir
  66. return thisVdir
  67. }
  68. }
  69. return nil
  70. }
  71. // Delete a vdir rule by its matching path
  72. func (ep *ProxyEndpoint) RemoveVirtualDirectoryRuleByMatchingPath(matchingPath string) error {
  73. entryFound := false
  74. newVirtualDirectoryList := []*VirtualDirectoryEndpoint{}
  75. for _, vdir := range ep.VirtualDirectories {
  76. if vdir.MatchingPath == matchingPath {
  77. entryFound = true
  78. } else {
  79. newVirtualDirectoryList = append(newVirtualDirectoryList, vdir)
  80. }
  81. }
  82. if entryFound {
  83. //Update the list of vdirs
  84. ep.VirtualDirectories = newVirtualDirectoryList
  85. return nil
  86. }
  87. return errors.New("target virtual directory routing rule not found")
  88. }
  89. // Delete a vdir rule by its matching path
  90. func (ep *ProxyEndpoint) AddVirtualDirectoryRule(vdir *VirtualDirectoryEndpoint) (*ProxyEndpoint, error) {
  91. //Check for matching path duplicate
  92. if ep.GetVirtualDirectoryRuleByMatchingPath(vdir.MatchingPath) != nil {
  93. return nil, errors.New("rule with same matching path already exists")
  94. }
  95. //Append it to the list of virtual directory
  96. ep.VirtualDirectories = append(ep.VirtualDirectories, vdir)
  97. //Prepare to replace the current routing rule
  98. parentRouter := ep.parent
  99. readyRoutingRule, err := parentRouter.PrepareProxyRoute(ep)
  100. if err != nil {
  101. return nil, err
  102. }
  103. if ep.ProxyType == ProxyType_Root {
  104. parentRouter.Root = readyRoutingRule
  105. } else if ep.ProxyType == ProxyType_Host {
  106. ep.Remove()
  107. parentRouter.AddProxyRouteToRuntime(readyRoutingRule)
  108. } else {
  109. return nil, errors.New("unsupported proxy type")
  110. }
  111. return readyRoutingRule, nil
  112. }
  113. // Check if the proxy endpoint hostname or alias name contains subdomain wildcard
  114. func (ep *ProxyEndpoint) ContainsWildcardName(skipAliasCheck bool) bool {
  115. hostname := ep.RootOrMatchingDomain
  116. aliasHostnames := ep.MatchingDomainAlias
  117. wildcardCheck := func(hostname string) bool {
  118. return len(hostname) > 0 && hostname[0] == '*'
  119. }
  120. if wildcardCheck(hostname) {
  121. return true
  122. }
  123. if !skipAliasCheck {
  124. for _, aliasHostname := range aliasHostnames {
  125. if wildcardCheck(aliasHostname) {
  126. return true
  127. }
  128. }
  129. }
  130. return false
  131. }
  132. // Create a deep clone object of the proxy endpoint
  133. // Note the returned object is not activated. Call to prepare function before pushing into runtime
  134. func (ep *ProxyEndpoint) Clone() *ProxyEndpoint {
  135. clonedProxyEndpoint := ProxyEndpoint{}
  136. js, _ := json.Marshal(ep)
  137. json.Unmarshal(js, &clonedProxyEndpoint)
  138. return &clonedProxyEndpoint
  139. }
  140. // Remove this proxy endpoint from running proxy endpoint list
  141. func (ep *ProxyEndpoint) Remove() error {
  142. ep.parent.ProxyEndpoints.Delete(ep.RootOrMatchingDomain)
  143. return nil
  144. }
  145. // Write changes to runtime without respawning the proxy handler
  146. // use prepare -> remove -> add if you change anything in the endpoint
  147. // that effects the proxy routing src / dest
  148. func (ep *ProxyEndpoint) UpdateToRuntime() {
  149. ep.parent.ProxyEndpoints.Store(ep.RootOrMatchingDomain, ep)
  150. }