@@ -92,10 +92,10 @@ var (
92
92
ShortLinkPattern = regexp .MustCompile (`(\[\[.*\]\]\w*)` )
93
93
94
94
// AnySHA1Pattern allows to split url containing SHA into parts
95
- AnySHA1Pattern = regexp .MustCompile (`http\S+ //(\S+)/(\S+)/(\S+)/(\S+)/([0-9a-f]{40})(?:/?([^#\s]+)?(?:#(\S+))?)?` )
95
+ AnySHA1Pattern = regexp .MustCompile (`( http\S*): //(\S+)/(\S+)/(\S+)/(\S+)/([0-9a-f]{40})(?:/?([^#\s]+)?(?:#(\S+))?)?` )
96
96
97
97
// IssueFullPattern allows to split issue (and pull) URLs into parts
98
- IssueFullPattern = regexp .MustCompile (`(?:^|\s|\()http\S+ //((?:[^\s/]+/)+)((?:\w{1,10}-)?[1-9][0-9]*)([\?|#]\S+.(\S+)?)?\b` )
98
+ IssueFullPattern = regexp .MustCompile (`(?:^|\s|\()( http\S*): //((?:[^\s/]+/)+)((?:\w{1,10}-)?[1-9][0-9]*)([\?|#]\S+.(\S+)?)?\b` )
99
99
100
100
validLinksPattern = regexp .MustCompile (`^[a-z][\w-]+://` )
101
101
)
@@ -126,10 +126,11 @@ type Renderer struct {
126
126
func (r * Renderer ) Link (out * bytes.Buffer , link []byte , title []byte , content []byte ) {
127
127
if len (link ) > 0 && ! isLink (link ) {
128
128
if link [0 ] != '#' {
129
- mLink := URLJoin ( r . urlPrefix , string (link ) )
129
+ lnk := string (link )
130
130
if r .isUncycloMarkdown {
131
- mLink = URLJoin (r . urlPrefix , "wiki" , string ( link ) )
131
+ lnk = URLJoin ("wiki" , lnk )
132
132
}
133
+ mLink := URLJoin (r .urlPrefix , lnk )
133
134
link = []byte (mLink )
134
135
}
135
136
}
@@ -206,12 +207,10 @@ func (r *Renderer) Image(out *bytes.Buffer, link []byte, title []byte, alt []byt
206
207
return
207
208
}
208
209
} else {
209
- if link [0 ] != '/' {
210
- if ! strings .HasSuffix (prefix , "/" ) {
211
- prefix += "/"
212
- }
213
- }
214
- link = []byte (url .QueryEscape (prefix + string (link )))
210
+ lnk := string (link )
211
+ lnk = URLJoin (prefix , lnk )
212
+ lnk = strings .Replace (lnk , " " , "+" , - 1 )
213
+ link = []byte (lnk )
215
214
}
216
215
}
217
216
@@ -246,10 +245,30 @@ func URLJoin(elem ...string) string {
246
245
last := len (elem ) - 1
247
246
for i , item := range elem {
248
247
res += item
249
- if ! strings .HasSuffix (res , "/" ) && i != last {
248
+ if i != last && ! strings .HasSuffix (res , "/" ) {
250
249
res += "/"
251
250
}
252
251
}
252
+ cwdIndex := strings .Index (res , "/./" )
253
+ for cwdIndex != - 1 {
254
+ res = strings .Replace (res , "/./" , "/" , 1 )
255
+ cwdIndex = strings .Index (res , "/./" )
256
+ }
257
+ upIndex := strings .Index (res , "/.." )
258
+ for upIndex != - 1 {
259
+ res = strings .Replace (res , "/.." , "" , 1 )
260
+ prevStart := - 1
261
+ for i := upIndex - 1 ; i >= 0 ; i -- {
262
+ if res [i ] == '/' {
263
+ prevStart = i
264
+ break
265
+ }
266
+ }
267
+ if prevStart != - 1 {
268
+ res = res [:prevStart ] + res [upIndex :]
269
+ }
270
+ upIndex = strings .Index (res , "/.." )
271
+ }
253
272
return res
254
273
}
255
274
@@ -286,6 +305,9 @@ func RenderIssueIndexPattern(rawBytes []byte, urlPrefix string, metas map[string
286
305
287
306
// IsSameDomain checks if given url string has the same hostname as current Gitea instance
288
307
func IsSameDomain (s string ) bool {
308
+ if strings .HasPrefix (s , "/" ) {
309
+ return true
310
+ }
289
311
if uapp , err := url .Parse (setting .AppURL ); err == nil {
290
312
if u , err := url .Parse (s ); err == nil {
291
313
return u .Host == uapp .Host
@@ -300,26 +322,27 @@ func renderFullSha1Pattern(rawBytes []byte, urlPrefix string) []byte {
300
322
ms := AnySHA1Pattern .FindAllSubmatch (rawBytes , - 1 )
301
323
for _ , m := range ms {
302
324
all := m [0 ]
303
- paths := string (m [1 ])
304
- var path = "//" + paths
305
- author := string (m [2 ])
306
- repoName := string (m [3 ])
325
+ protocol := string (m [1 ])
326
+ paths := string (m [2 ])
327
+ path := protocol + "://" + paths
328
+ author := string (m [3 ])
329
+ repoName := string (m [4 ])
307
330
path = URLJoin (path , author , repoName )
308
331
ltype := "src"
309
- itemType := m [4 ]
332
+ itemType := m [5 ]
310
333
if IsSameDomain (paths ) {
311
334
ltype = string (itemType )
312
335
} else if string (itemType ) == "commit" {
313
336
ltype = "commit"
314
337
}
315
- sha := m [5 ]
338
+ sha := m [6 ]
316
339
var subtree string
317
- if len (m ) > 6 && len (m [6 ]) > 0 {
318
- subtree = string (m [6 ])
340
+ if len (m ) > 7 && len (m [7 ]) > 0 {
341
+ subtree = string (m [7 ])
319
342
}
320
343
var line []byte
321
- if len (m ) > 7 && len (m [7 ]) > 0 {
322
- line = m [7 ]
344
+ if len (m ) > 8 && len (m [8 ]) > 0 {
345
+ line = m [8 ]
323
346
}
324
347
urlSuffix := ""
325
348
text := base .ShortSha (string (sha ))
@@ -346,23 +369,18 @@ func renderFullIssuePattern(rawBytes []byte, urlPrefix string) []byte {
346
369
ms := IssueFullPattern .FindAllSubmatch (rawBytes , - 1 )
347
370
for _ , m := range ms {
348
371
all := m [0 ]
349
- paths := bytes .Split (m [1 ], []byte ("/" ))
372
+ protocol := string (m [1 ])
373
+ paths := bytes .Split (m [2 ], []byte ("/" ))
350
374
paths = paths [:len (paths )- 1 ]
351
375
if bytes .HasPrefix (paths [0 ], []byte ("gist." )) {
352
376
continue
353
377
}
354
- var path string
355
- if len (paths ) > 3 {
356
- // Internal one
357
- path = URLJoin (urlPrefix , "issues" )
358
- } else {
359
- path = "//" + string (m [1 ])
360
- }
361
- id := string (m [2 ])
378
+ path := protocol + "://" + string (m [2 ])
379
+ id := string (m [3 ])
362
380
path = URLJoin (path , id )
363
381
var comment []byte
364
382
if len (m ) > 3 {
365
- comment = m [3 ]
383
+ comment = m [4 ]
366
384
}
367
385
urlSuffix := ""
368
386
text := "#" + id
@@ -394,8 +412,13 @@ func lastIndexOfByte(sl []byte, target byte) int {
394
412
return - 1
395
413
}
396
414
397
- // renderShortLinks processes [[syntax]]
398
- func renderShortLinks (rawBytes []byte , urlPrefix string , noLink bool ) []byte {
415
+ // RenderShortLinks processes [[syntax]]
416
+ //
417
+ // noLink flag disables making link tags when set to true
418
+ // so this function just replaces the whole [[...]] with the content text
419
+ //
420
+ // isUncycloMarkdown is a flag to choose linking url prefix
421
+ func RenderShortLinks (rawBytes []byte , urlPrefix string , noLink bool , isUncycloMarkdown bool ) []byte {
399
422
ms := ShortLinkPattern .FindAll (rawBytes , - 1 )
400
423
for _ , m := range ms {
401
424
orig := bytes .TrimSpace (m )
@@ -482,11 +505,17 @@ func renderShortLinks(rawBytes []byte, urlPrefix string, noLink bool) []byte {
482
505
}
483
506
absoluteLink := isLink ([]byte (link ))
484
507
if ! absoluteLink {
485
- link = url . QueryEscape (link )
508
+ link = strings . Replace (link , " " , "+" , - 1 )
486
509
}
487
510
if image {
488
511
if ! absoluteLink {
489
- link = URLJoin (urlPrefix , "wiki" , "raw" , link )
512
+ if IsSameDomain (urlPrefix ) {
513
+ urlPrefix = strings .Replace (urlPrefix , "/src/" , "/raw/" , 1 )
514
+ }
515
+ if isUncycloMarkdown {
516
+ link = URLJoin ("wiki" , "raw" , link )
517
+ }
518
+ link = URLJoin (urlPrefix , link )
490
519
}
491
520
title := props ["title" ]
492
521
if title == "" {
@@ -504,7 +533,10 @@ func renderShortLinks(rawBytes []byte, urlPrefix string, noLink bool) []byte {
504
533
}
505
534
name = fmt .Sprintf (`<img src="%s" %s title="%s" />` , link , alt , title )
506
535
} else if ! absoluteLink {
507
- link = URLJoin (urlPrefix , "wiki" , link )
536
+ if isUncycloMarkdown {
537
+ link = URLJoin ("wiki" , link )
538
+ }
539
+ link = URLJoin (urlPrefix , link )
508
540
}
509
541
if noLink {
510
542
rawBytes = bytes .Replace (rawBytes , orig , []byte (name ), - 1 )
@@ -527,7 +559,7 @@ func RenderCrossReferenceIssueIndexPattern(rawBytes []byte, urlPrefix string, me
527
559
repo := string (bytes .Split (m , []byte ("#" ))[0 ])
528
560
issue := string (bytes .Split (m , []byte ("#" ))[1 ])
529
561
530
- link := fmt .Sprintf (`<a href="%s">%s</a>` , URLJoin (urlPrefix , repo , "issues" , issue ), m )
562
+ link := fmt .Sprintf (`<a href="%s">%s</a>` , URLJoin (setting . AppURL , repo , "issues" , issue ), m )
531
563
rawBytes = bytes .Replace (rawBytes , m , []byte (link ), 1 )
532
564
}
533
565
return rawBytes
@@ -548,15 +580,15 @@ func renderSha1CurrentPattern(rawBytes []byte, urlPrefix string) []byte {
548
580
}
549
581
550
582
// RenderSpecialLink renders mentions, indexes and SHA1 strings to corresponding links.
551
- func RenderSpecialLink (rawBytes []byte , urlPrefix string , metas map [string ]string ) []byte {
583
+ func RenderSpecialLink (rawBytes []byte , urlPrefix string , metas map [string ]string , isUncycloMarkdown bool ) []byte {
552
584
ms := MentionPattern .FindAll (rawBytes , - 1 )
553
585
for _ , m := range ms {
554
586
m = m [bytes .Index (m , []byte ("@" )):]
555
587
rawBytes = bytes .Replace (rawBytes , m ,
556
588
[]byte (fmt .Sprintf (`<a href="%s">%s</a>` , URLJoin (setting .AppURL , string (m [1 :])), m )), - 1 )
557
589
}
558
590
559
- rawBytes = renderShortLinks (rawBytes , urlPrefix , false )
591
+ rawBytes = RenderShortLinks (rawBytes , urlPrefix , false , isUncycloMarkdown )
560
592
rawBytes = RenderIssueIndexPattern (rawBytes , urlPrefix , metas )
561
593
rawBytes = RenderCrossReferenceIssueIndexPattern (rawBytes , urlPrefix , metas )
562
594
rawBytes = renderFullSha1Pattern (rawBytes , urlPrefix )
@@ -601,7 +633,7 @@ var noEndTags = []string{"img", "input", "br", "hr"}
601
633
602
634
// PostProcess treats different types of HTML differently,
603
635
// and only renders special links for plain text blocks.
604
- func PostProcess (rawHTML []byte , urlPrefix string , metas map [string ]string ) []byte {
636
+ func PostProcess (rawHTML []byte , urlPrefix string , metas map [string ]string , isUncycloMarkdown bool ) []byte {
605
637
startTags := make ([]string , 0 , 5 )
606
638
var buf bytes.Buffer
607
639
tokenizer := html .NewTokenizer (bytes .NewReader (rawHTML ))
@@ -611,7 +643,7 @@ OUTER_LOOP:
611
643
token := tokenizer .Token ()
612
644
switch token .Type {
613
645
case html .TextToken :
614
- buf .Write (RenderSpecialLink ([]byte (token .String ()), urlPrefix , metas ))
646
+ buf .Write (RenderSpecialLink ([]byte (token .String ()), urlPrefix , metas , isUncycloMarkdown ))
615
647
616
648
case html .StartTagToken :
617
649
buf .WriteString (token .String ())
@@ -623,7 +655,7 @@ OUTER_LOOP:
623
655
token = tokenizer .Token ()
624
656
625
657
// Copy the token to the output verbatim
626
- buf .Write (renderShortLinks ([]byte (token .String ()), urlPrefix , true ))
658
+ buf .Write (RenderShortLinks ([]byte (token .String ()), urlPrefix , true , isUncycloMarkdown ))
627
659
628
660
if token .Type == html .StartTagToken {
629
661
if ! com .IsSliceContainsStr (noEndTags , token .Data ) {
@@ -673,9 +705,9 @@ OUTER_LOOP:
673
705
674
706
// Render renders Markdown to HTML with all specific handling stuff.
675
707
func render (rawBytes []byte , urlPrefix string , metas map [string ]string , isUncycloMarkdown bool ) []byte {
676
- urlPrefix = strings .Replace (urlPrefix , " " , "%20 " , - 1 )
708
+ urlPrefix = strings .Replace (urlPrefix , " " , "+ " , - 1 )
677
709
result := RenderRaw (rawBytes , urlPrefix , isUncycloMarkdown )
678
- result = PostProcess (result , urlPrefix , metas )
710
+ result = PostProcess (result , urlPrefix , metas , isUncycloMarkdown )
679
711
result = Sanitizer .SanitizeBytes (result )
680
712
return result
681
713
}
0 commit comments