github.com/sirkon/goproxy@v1.4.8/tree.go (about)

     1  package goproxy
     2  
     3  import (
     4  	"strings"
     5  
     6  	"github.com/sirkon/goproxy/internal/errors"
     7  )
     8  
     9  type nodeExtension struct {
    10  	path string
    11  	node *node
    12  }
    13  
    14  type node struct {
    15  	f       Plugin
    16  	further []*nodeExtension
    17  }
    18  
    19  func (n *node) addNode(path string, f Plugin) error {
    20  	return n.realAdd(path, path, f)
    21  }
    22  
    23  func (n *node) getNode(path string) Plugin {
    24  	return n.realGet(path, path)
    25  }
    26  
    27  func (n *node) realAdd(path string, origPath string, f Plugin) error {
    28  	if len(path) == 0 {
    29  		if n.f == nil {
    30  			n.f = f
    31  		} else {
    32  			return errors.Newf("cannot prolong a node with given path %s as it was taken before", origPath)
    33  		}
    34  		return nil
    35  	}
    36  
    37  	for _, ne := range n.further {
    38  		switch {
    39  		case strings.HasPrefix(path, ne.path):
    40  			return ne.node.realAdd(path[len(ne.path):], origPath, f)
    41  		case strings.HasPrefix(ne.path, path):
    42  			// decompose a path
    43  			tail := ne.path[len(path):]
    44  			newNode := &node{
    45  				f: f,
    46  				further: []*nodeExtension{
    47  					{
    48  						path: tail,
    49  						node: ne.node,
    50  					},
    51  				},
    52  			}
    53  			ne.path = path
    54  			ne.node = newNode
    55  			return nil
    56  		default:
    57  			cp := commonPrefix(path, ne.path)
    58  			if len(cp) > 0 {
    59  				tail1 := path[len(cp):]
    60  				tail2 := ne.path[len(cp):]
    61  				newNode := &node{
    62  					further: []*nodeExtension{
    63  						{
    64  							path: tail1,
    65  							node: &node{
    66  								f: f,
    67  							},
    68  						},
    69  						{
    70  							path: tail2,
    71  							node: ne.node,
    72  						},
    73  					},
    74  				}
    75  				ne.path = cp
    76  				ne.node = newNode
    77  				return nil
    78  			}
    79  		}
    80  	}
    81  
    82  	n.further = append(n.further, &nodeExtension{
    83  		path: path,
    84  		node: &node{
    85  			f: f,
    86  		},
    87  	})
    88  
    89  	return nil
    90  }
    91  
    92  func commonPrefix(p1 string, p2 string) string {
    93  	for i := range p1 {
    94  		// it is clear we will stop before the end of either strings
    95  		if p1[i] != p2[i] {
    96  			return p1[:i]
    97  		}
    98  	}
    99  	return ""
   100  }
   101  
   102  func (n *node) realGet(path string, origPath string) Plugin {
   103  	for _, ne := range n.further {
   104  		if strings.HasPrefix(path, ne.path) {
   105  			res := ne.node.realGet(path[len(ne.path):], origPath)
   106  			if res == nil {
   107  				return n.f
   108  			}
   109  			return res
   110  		}
   111  	}
   112  	return n.f
   113  }