1
2
3
4
5 package mux
6
7 import (
8 "errors"
9 "fmt"
10 "net/http"
11 "net/url"
12 "regexp"
13 "strings"
14 )
15
16
17 type Route struct {
18
19 handler http.Handler
20
21 buildOnly bool
22
23 name string
24
25 err error
26
27
28 namedRoutes map[string]*Route
29
30
31 routeConf
32 }
33
34
35
36 func (r *Route) SkipClean() bool {
37 return r.skipClean
38 }
39
40
41 func (r *Route) Match(req *http.Request, match *RouteMatch) bool {
42 if r.buildOnly || r.err != nil {
43 return false
44 }
45
46 var matchErr error
47
48
49 for _, m := range r.matchers {
50 if matched := m.Match(req, match); !matched {
51 if _, ok := m.(methodMatcher); ok {
52 matchErr = ErrMethodMismatch
53 continue
54 }
55
56
57
58
59
60
61
62
63 if match.MatchErr == ErrNotFound {
64 match.MatchErr = nil
65 }
66
67 matchErr = nil
68 return false
69 } else {
70
71
72
73
74
75
76 if match.MatchErr == ErrMethodMismatch {
77 match.MatchErr = nil
78 }
79 }
80 }
81
82 if matchErr != nil {
83 match.MatchErr = matchErr
84 return false
85 }
86
87 if match.MatchErr == ErrMethodMismatch && r.handler != nil {
88
89 match.MatchErr = nil
90
91 match.Handler = r.handler
92 }
93
94
95 if match.Route == nil {
96 match.Route = r
97 }
98 if match.Handler == nil {
99 match.Handler = r.handler
100 }
101 if match.Vars == nil {
102 match.Vars = make(map[string]string)
103 }
104
105
106 r.regexp.setMatch(req, match, r)
107 return true
108 }
109
110
111
112
113
114
115 func (r *Route) GetError() error {
116 return r.err
117 }
118
119
120 func (r *Route) BuildOnly() *Route {
121 r.buildOnly = true
122 return r
123 }
124
125
126
127
128 func (r *Route) Handler(handler http.Handler) *Route {
129 if r.err == nil {
130 r.handler = handler
131 }
132 return r
133 }
134
135
136 func (r *Route) HandlerFunc(f func(http.ResponseWriter, *http.Request)) *Route {
137 return r.Handler(http.HandlerFunc(f))
138 }
139
140
141 func (r *Route) GetHandler() http.Handler {
142 return r.handler
143 }
144
145
146
147
148
149 func (r *Route) Name(name string) *Route {
150 if r.name != "" {
151 r.err = fmt.Errorf("mux: route already has name %q, can't set %q",
152 r.name, name)
153 }
154 if r.err == nil {
155 r.name = name
156 r.namedRoutes[name] = r
157 }
158 return r
159 }
160
161
162 func (r *Route) GetName() string {
163 return r.name
164 }
165
166
167
168
169
170
171 type matcher interface {
172 Match(*http.Request, *RouteMatch) bool
173 }
174
175
176 func (r *Route) addMatcher(m matcher) *Route {
177 if r.err == nil {
178 r.matchers = append(r.matchers, m)
179 }
180 return r
181 }
182
183
184 func (r *Route) addRegexpMatcher(tpl string, typ regexpType) error {
185 if r.err != nil {
186 return r.err
187 }
188 if typ == regexpTypePath || typ == regexpTypePrefix {
189 if len(tpl) > 0 && tpl[0] != '/' {
190 return fmt.Errorf("mux: path must start with a slash, got %q", tpl)
191 }
192 if r.regexp.path != nil {
193 tpl = strings.TrimRight(r.regexp.path.template, "/") + tpl
194 }
195 }
196 rr, err := newRouteRegexp(tpl, typ, routeRegexpOptions{
197 strictSlash: r.strictSlash,
198 useEncodedPath: r.useEncodedPath,
199 })
200 if err != nil {
201 return err
202 }
203 for _, q := range r.regexp.queries {
204 if err = uniqueVars(rr.varsN, q.varsN); err != nil {
205 return err
206 }
207 }
208 if typ == regexpTypeHost {
209 if r.regexp.path != nil {
210 if err = uniqueVars(rr.varsN, r.regexp.path.varsN); err != nil {
211 return err
212 }
213 }
214 r.regexp.host = rr
215 } else {
216 if r.regexp.host != nil {
217 if err = uniqueVars(rr.varsN, r.regexp.host.varsN); err != nil {
218 return err
219 }
220 }
221 if typ == regexpTypeQuery {
222 r.regexp.queries = append(r.regexp.queries, rr)
223 } else {
224 r.regexp.path = rr
225 }
226 }
227 r.addMatcher(rr)
228 return nil
229 }
230
231
232
233
234 type headerMatcher map[string]string
235
236 func (m headerMatcher) Match(r *http.Request, match *RouteMatch) bool {
237 return matchMapWithString(m, r.Header, true)
238 }
239
240
241
242
243
244
245
246
247
248
249 func (r *Route) Headers(pairs ...string) *Route {
250 if r.err == nil {
251 var headers map[string]string
252 headers, r.err = mapFromPairsToString(pairs...)
253 return r.addMatcher(headerMatcher(headers))
254 }
255 return r
256 }
257
258
259 type headerRegexMatcher map[string]*regexp.Regexp
260
261 func (m headerRegexMatcher) Match(r *http.Request, match *RouteMatch) bool {
262 return matchMapWithRegex(m, r.Header, true)
263 }
264
265
266
267
268
269
270
271
272
273
274
275 func (r *Route) HeadersRegexp(pairs ...string) *Route {
276 if r.err == nil {
277 var headers map[string]*regexp.Regexp
278 headers, r.err = mapFromPairsToRegex(pairs...)
279 return r.addMatcher(headerRegexMatcher(headers))
280 }
281 return r
282 }
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303 func (r *Route) Host(tpl string) *Route {
304 r.err = r.addRegexpMatcher(tpl, regexpTypeHost)
305 return r
306 }
307
308
309
310
311 type MatcherFunc func(*http.Request, *RouteMatch) bool
312
313
314 func (m MatcherFunc) Match(r *http.Request, match *RouteMatch) bool {
315 return m(r, match)
316 }
317
318
319 func (r *Route) MatcherFunc(f MatcherFunc) *Route {
320 return r.addMatcher(f)
321 }
322
323
324
325
326 type methodMatcher []string
327
328 func (m methodMatcher) Match(r *http.Request, match *RouteMatch) bool {
329 return matchInArray(m, r.Method)
330 }
331
332
333
334
335 func (r *Route) Methods(methods ...string) *Route {
336 for k, v := range methods {
337 methods[k] = strings.ToUpper(v)
338 }
339 return r.addMatcher(methodMatcher(methods))
340 }
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363 func (r *Route) Path(tpl string) *Route {
364 r.err = r.addRegexpMatcher(tpl, regexpTypePath)
365 return r
366 }
367
368
369
370
371
372
373
374
375
376
377
378
379 func (r *Route) PathPrefix(tpl string) *Route {
380 r.err = r.addRegexpMatcher(tpl, regexpTypePrefix)
381 return r
382 }
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403 func (r *Route) Queries(pairs ...string) *Route {
404 length := len(pairs)
405 if length%2 != 0 {
406 r.err = fmt.Errorf(
407 "mux: number of parameters must be multiple of 2, got %v", pairs)
408 return nil
409 }
410 for i := 0; i < length; i += 2 {
411 if r.err = r.addRegexpMatcher(pairs[i]+"="+pairs[i+1], regexpTypeQuery); r.err != nil {
412 return r
413 }
414 }
415
416 return r
417 }
418
419
420
421
422 type schemeMatcher []string
423
424 func (m schemeMatcher) Match(r *http.Request, match *RouteMatch) bool {
425 scheme := r.URL.Scheme
426
427
428
429
430
431 if scheme == "" {
432 if r.TLS == nil {
433 scheme = "http"
434 } else {
435 scheme = "https"
436 }
437 }
438 return matchInArray(m, scheme)
439 }
440
441
442
443
444
445
446
447
448
449 func (r *Route) Schemes(schemes ...string) *Route {
450 for k, v := range schemes {
451 schemes[k] = strings.ToLower(v)
452 }
453 if len(schemes) > 0 {
454 r.buildScheme = schemes[0]
455 }
456 return r.addMatcher(schemeMatcher(schemes))
457 }
458
459
460
461
462
463 type BuildVarsFunc func(map[string]string) map[string]string
464
465
466
467 func (r *Route) BuildVarsFunc(f BuildVarsFunc) *Route {
468 if r.buildVarsFunc != nil {
469
470 old := r.buildVarsFunc
471 r.buildVarsFunc = func(m map[string]string) map[string]string {
472 return f(old(m))
473 }
474 } else {
475 r.buildVarsFunc = f
476 }
477 return r
478 }
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494 func (r *Route) Subrouter() *Router {
495
496 router := &Router{routeConf: copyRouteConf(r.routeConf), namedRoutes: r.namedRoutes}
497 r.addMatcher(router)
498 return router
499 }
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543 func (r *Route) URL(pairs ...string) (*url.URL, error) {
544 if r.err != nil {
545 return nil, r.err
546 }
547 values, err := r.prepareVars(pairs...)
548 if err != nil {
549 return nil, err
550 }
551 var scheme, host, path string
552 queries := make([]string, 0, len(r.regexp.queries))
553 if r.regexp.host != nil {
554 if host, err = r.regexp.host.url(values); err != nil {
555 return nil, err
556 }
557 scheme = "http"
558 if r.buildScheme != "" {
559 scheme = r.buildScheme
560 }
561 }
562 if r.regexp.path != nil {
563 if path, err = r.regexp.path.url(values); err != nil {
564 return nil, err
565 }
566 }
567 for _, q := range r.regexp.queries {
568 var query string
569 if query, err = q.url(values); err != nil {
570 return nil, err
571 }
572 queries = append(queries, query)
573 }
574 return &url.URL{
575 Scheme: scheme,
576 Host: host,
577 Path: path,
578 RawQuery: strings.Join(queries, "&"),
579 }, nil
580 }
581
582
583
584
585 func (r *Route) URLHost(pairs ...string) (*url.URL, error) {
586 if r.err != nil {
587 return nil, r.err
588 }
589 if r.regexp.host == nil {
590 return nil, errors.New("mux: route doesn't have a host")
591 }
592 values, err := r.prepareVars(pairs...)
593 if err != nil {
594 return nil, err
595 }
596 host, err := r.regexp.host.url(values)
597 if err != nil {
598 return nil, err
599 }
600 u := &url.URL{
601 Scheme: "http",
602 Host: host,
603 }
604 if r.buildScheme != "" {
605 u.Scheme = r.buildScheme
606 }
607 return u, nil
608 }
609
610
611
612
613 func (r *Route) URLPath(pairs ...string) (*url.URL, error) {
614 if r.err != nil {
615 return nil, r.err
616 }
617 if r.regexp.path == nil {
618 return nil, errors.New("mux: route doesn't have a path")
619 }
620 values, err := r.prepareVars(pairs...)
621 if err != nil {
622 return nil, err
623 }
624 path, err := r.regexp.path.url(values)
625 if err != nil {
626 return nil, err
627 }
628 return &url.URL{
629 Path: path,
630 }, nil
631 }
632
633
634
635
636
637
638 func (r *Route) GetPathTemplate() (string, error) {
639 if r.err != nil {
640 return "", r.err
641 }
642 if r.regexp.path == nil {
643 return "", errors.New("mux: route doesn't have a path")
644 }
645 return r.regexp.path.template, nil
646 }
647
648
649
650
651
652 func (r *Route) GetPathRegexp() (string, error) {
653 if r.err != nil {
654 return "", r.err
655 }
656 if r.regexp.path == nil {
657 return "", errors.New("mux: route does not have a path")
658 }
659 return r.regexp.path.regexp.String(), nil
660 }
661
662
663
664
665
666
667 func (r *Route) GetQueriesRegexp() ([]string, error) {
668 if r.err != nil {
669 return nil, r.err
670 }
671 if r.regexp.queries == nil {
672 return nil, errors.New("mux: route doesn't have queries")
673 }
674 queries := make([]string, 0, len(r.regexp.queries))
675 for _, query := range r.regexp.queries {
676 queries = append(queries, query.regexp.String())
677 }
678 return queries, nil
679 }
680
681
682
683
684
685
686 func (r *Route) GetQueriesTemplates() ([]string, error) {
687 if r.err != nil {
688 return nil, r.err
689 }
690 if r.regexp.queries == nil {
691 return nil, errors.New("mux: route doesn't have queries")
692 }
693 queries := make([]string, 0, len(r.regexp.queries))
694 for _, query := range r.regexp.queries {
695 queries = append(queries, query.template)
696 }
697 return queries, nil
698 }
699
700
701
702
703
704 func (r *Route) GetMethods() ([]string, error) {
705 if r.err != nil {
706 return nil, r.err
707 }
708 for _, m := range r.matchers {
709 if methods, ok := m.(methodMatcher); ok {
710 return []string(methods), nil
711 }
712 }
713 return nil, errors.New("mux: route doesn't have methods")
714 }
715
716
717
718
719
720
721 func (r *Route) GetHostTemplate() (string, error) {
722 if r.err != nil {
723 return "", r.err
724 }
725 if r.regexp.host == nil {
726 return "", errors.New("mux: route doesn't have a host")
727 }
728 return r.regexp.host.template, nil
729 }
730
731
732
733 func (r *Route) GetVarNames() ([]string, error) {
734 if r.err != nil {
735 return nil, r.err
736 }
737 var varNames []string
738 if r.regexp.host != nil {
739 varNames = append(varNames, r.regexp.host.varsN...)
740 }
741 if r.regexp.path != nil {
742 varNames = append(varNames, r.regexp.path.varsN...)
743 }
744 for _, regx := range r.regexp.queries {
745 varNames = append(varNames, regx.varsN...)
746 }
747 return varNames, nil
748 }
749
750
751
752 func (r *Route) prepareVars(pairs ...string) (map[string]string, error) {
753 m, err := mapFromPairsToString(pairs...)
754 if err != nil {
755 return nil, err
756 }
757 return r.buildVars(m), nil
758 }
759
760 func (r *Route) buildVars(m map[string]string) map[string]string {
761 if r.buildVarsFunc != nil {
762 m = r.buildVarsFunc(m)
763 }
764 return m
765 }
766
View as plain text