Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Support
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
C
caddy
Project overview
Project overview
Details
Activity
Releases
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Issues
0
Issues
0
List
Boards
Labels
Milestones
Merge Requests
0
Merge Requests
0
Analytics
Analytics
Repository
Value Stream
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Create a new issue
Commits
Issue Boards
Open sidebar
nexedi
caddy
Commits
7b29568e
Commit
7b29568e
authored
Jul 29, 2015
by
Abiola Ibrahim
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Code cleanups.
Fix more race conditions.
parent
e240cd5b
Changes
4
Hide whitespace changes
Inline
Side-by-side
Showing
4 changed files
with
135 additions
and
40 deletions
+135
-40
middleware/markdown/markdown.go
middleware/markdown/markdown.go
+10
-8
middleware/markdown/markdown_test.go
middleware/markdown/markdown_test.go
+47
-12
middleware/markdown/page.go
middleware/markdown/page.go
+76
-18
middleware/markdown/process.go
middleware/markdown/process.go
+2
-2
No files found.
middleware/markdown/markdown.go
View file @
7b29568e
...
@@ -4,13 +4,14 @@ package markdown
...
@@ -4,13 +4,14 @@ package markdown
import
(
import
(
"io/ioutil"
"io/ioutil"
"log"
"net/http"
"net/http"
"os"
"os"
"strings"
"strings"
"sync"
"github.com/mholt/caddy/middleware"
"github.com/mholt/caddy/middleware"
"github.com/russross/blackfriday"
"github.com/russross/blackfriday"
// "log"
)
)
// Markdown implements a layer of middleware that serves
// Markdown implements a layer of middleware that serves
...
@@ -70,11 +71,14 @@ type Config struct {
...
@@ -70,11 +71,14 @@ type Config struct {
// Directory to store static files
// Directory to store static files
StaticDir
string
StaticDir
string
sync
.
RWMutex
}
}
// ServeHTTP implements the http.Handler interface.
// ServeHTTP implements the http.Handler interface.
func
(
md
Markdown
)
ServeHTTP
(
w
http
.
ResponseWriter
,
r
*
http
.
Request
)
(
int
,
error
)
{
func
(
md
Markdown
)
ServeHTTP
(
w
http
.
ResponseWriter
,
r
*
http
.
Request
)
(
int
,
error
)
{
for
_
,
m
:=
range
md
.
Configs
{
for
i
:=
range
md
.
Configs
{
m
:=
&
md
.
Configs
[
i
]
if
!
middleware
.
Path
(
r
.
URL
.
Path
)
.
Matches
(
m
.
PathScope
)
{
if
!
middleware
.
Path
(
r
.
URL
.
Path
)
.
Matches
(
m
.
PathScope
)
{
continue
continue
}
}
...
@@ -120,11 +124,9 @@ func (md Markdown) ServeHTTP(w http.ResponseWriter, r *http.Request) (int, error
...
@@ -120,11 +124,9 @@ func (md Markdown) ServeHTTP(w http.ResponseWriter, r *http.Request) (int, error
if
m
.
StaticDir
!=
""
{
if
m
.
StaticDir
!=
""
{
// Markdown modified or new. Update links.
// Markdown modified or new. Update links.
// go func() {
if
err
:=
GenerateLinks
(
md
,
m
);
err
!=
nil
{
// if err := GenerateLinks(md, &md.Configs[i]); err != nil {
log
.
Println
(
err
)
// log.Println(err)
}
// }
// }()
}
}
body
,
err
:=
ioutil
.
ReadAll
(
f
)
body
,
err
:=
ioutil
.
ReadAll
(
f
)
...
@@ -137,7 +139,7 @@ func (md Markdown) ServeHTTP(w http.ResponseWriter, r *http.Request) (int, error
...
@@ -137,7 +139,7 @@ func (md Markdown) ServeHTTP(w http.ResponseWriter, r *http.Request) (int, error
Req
:
r
,
Req
:
r
,
URL
:
r
.
URL
,
URL
:
r
.
URL
,
}
}
html
,
err
:=
md
.
Process
(
m
,
fpath
,
body
,
ctx
)
html
,
err
:=
md
.
Process
(
*
m
,
fpath
,
body
,
ctx
)
if
err
!=
nil
{
if
err
!=
nil
{
return
http
.
StatusInternalServerError
,
err
return
http
.
StatusInternalServerError
,
err
}
}
...
...
middleware/markdown/markdown_test.go
View file @
7b29568e
...
@@ -4,6 +4,7 @@ import (
...
@@ -4,6 +4,7 @@ import (
"net/http"
"net/http"
"net/http/httptest"
"net/http/httptest"
"strings"
"strings"
"sync"
"testing"
"testing"
"github.com/mholt/caddy/middleware"
"github.com/mholt/caddy/middleware"
...
@@ -18,20 +19,24 @@ func TestMarkdown(t *testing.T) {
...
@@ -18,20 +19,24 @@ func TestMarkdown(t *testing.T) {
FileSys
:
http
.
Dir
(
"./testdata"
),
FileSys
:
http
.
Dir
(
"./testdata"
),
Configs
:
[]
Config
{
Configs
:
[]
Config
{
Config
{
Config
{
Renderer
:
blackfriday
.
HtmlRenderer
(
0
,
""
,
""
),
Renderer
:
blackfriday
.
HtmlRenderer
(
0
,
""
,
""
),
PathScope
:
"/blog"
,
PathScope
:
"/blog"
,
Extensions
:
[]
string
{
".md"
},
Extensions
:
[]
string
{
".md"
},
Styles
:
[]
string
{},
Styles
:
[]
string
{},
Scripts
:
[]
string
{},
Scripts
:
[]
string
{},
Templates
:
templates
,
Templates
:
templates
,
StaticDir
:
DefaultStaticDir
,
StaticFiles
:
make
(
map
[
string
]
string
),
},
},
Config
{
Config
{
Renderer
:
blackfriday
.
HtmlRenderer
(
0
,
""
,
""
),
Renderer
:
blackfriday
.
HtmlRenderer
(
0
,
""
,
""
),
PathScope
:
"/log"
,
PathScope
:
"/log"
,
Extensions
:
[]
string
{
".md"
},
Extensions
:
[]
string
{
".md"
},
Styles
:
[]
string
{
"/resources/css/log.css"
,
"/resources/css/default.css"
},
Styles
:
[]
string
{
"/resources/css/log.css"
,
"/resources/css/default.css"
},
Scripts
:
[]
string
{
"/resources/js/log.js"
,
"/resources/js/default.js"
},
Scripts
:
[]
string
{
"/resources/js/log.js"
,
"/resources/js/default.js"
},
Templates
:
make
(
map
[
string
]
string
),
Templates
:
make
(
map
[
string
]
string
),
StaticDir
:
DefaultStaticDir
,
StaticFiles
:
make
(
map
[
string
]
string
),
},
},
},
},
IndexFiles
:
[]
string
{
"index.html"
},
IndexFiles
:
[]
string
{
"index.html"
},
...
@@ -123,4 +128,34 @@ func getTrue() bool {
...
@@ -123,4 +128,34 @@ func getTrue() bool {
if
respBody
!=
expectedBody
{
if
respBody
!=
expectedBody
{
t
.
Fatalf
(
"Expected body: %v got: %v"
,
expectedBody
,
respBody
)
t
.
Fatalf
(
"Expected body: %v got: %v"
,
expectedBody
,
respBody
)
}
}
expectedLinks
:=
[]
string
{
"/blog/test.md"
,
"/log/test.md"
,
}
for
i
,
c
:=
range
md
.
Configs
{
if
c
.
Links
[
0
]
.
Url
!=
expectedLinks
[
i
]
{
t
.
Fatalf
(
"Expected %v got %v"
,
expectedLinks
[
i
],
c
.
Links
[
0
]
.
Url
)
}
}
// attempt to trigger race condition
var
w
sync
.
WaitGroup
f
:=
func
()
{
req
,
err
:=
http
.
NewRequest
(
"GET"
,
"/log/test.md"
,
nil
)
if
err
!=
nil
{
t
.
Fatalf
(
"Could not create HTTP request: %v"
,
err
)
}
rec
:=
httptest
.
NewRecorder
()
md
.
ServeHTTP
(
rec
,
req
)
w
.
Done
()
}
for
i
:=
0
;
i
<
5
;
i
++
{
w
.
Add
(
1
)
go
f
()
}
w
.
Wait
()
}
}
middleware/markdown/page.go
View file @
7b29568e
...
@@ -12,17 +12,15 @@ import (
...
@@ -12,17 +12,15 @@ import (
"github.com/russross/blackfriday"
"github.com/russross/blackfriday"
)
)
var
(
pagesMutex
sync
.
RWMutex
linksGenerating
bool
)
const
(
const
(
// Date format YYYY-MM-DD HH:MM:SS
timeLayout
=
`2006-01-02 15:04:05`
timeLayout
=
`2006-01-02 15:04:05`
// Length of page summary.
summaryLen
=
150
summaryLen
=
150
)
)
// Page represents a statically generated markdown page.
// Page
Link
represents a statically generated markdown page.
type
PageLink
struct
{
type
PageLink
struct
{
Title
string
Title
string
Summary
string
Summary
string
...
@@ -30,25 +28,51 @@ type PageLink struct {
...
@@ -30,25 +28,51 @@ type PageLink struct {
Url
string
Url
string
}
}
// pageLinkSorter sort PageLink by newest date to oldest.
// pageLinkSorter sort
s
PageLink by newest date to oldest.
type
pageLinkSorter
[]
PageLink
type
pageLinkSorter
[]
PageLink
func
(
p
pageLinkSorter
)
Len
()
int
{
return
len
(
p
)
}
func
(
p
pageLinkSorter
)
Len
()
int
{
return
len
(
p
)
}
func
(
p
pageLinkSorter
)
Swap
(
i
,
j
int
)
{
p
[
i
],
p
[
j
]
=
p
[
j
],
p
[
i
]
}
func
(
p
pageLinkSorter
)
Swap
(
i
,
j
int
)
{
p
[
i
],
p
[
j
]
=
p
[
j
],
p
[
i
]
}
func
(
p
pageLinkSorter
)
Less
(
i
,
j
int
)
bool
{
return
p
[
i
]
.
Date
.
After
(
p
[
j
]
.
Date
)
}
func
(
p
pageLinkSorter
)
Less
(
i
,
j
int
)
bool
{
return
p
[
i
]
.
Date
.
After
(
p
[
j
]
.
Date
)
}
func
GenerateLinks
(
md
Markdown
,
cfg
*
Config
)
error
{
type
linkGen
struct
{
if
linksGenerating
{
generating
bool
return
nil
waiters
int
lastErr
error
sync
.
RWMutex
sync
.
WaitGroup
}
func
(
l
*
linkGen
)
addWaiter
()
{
l
.
WaitGroup
.
Add
(
1
)
l
.
waiters
++
}
func
(
l
*
linkGen
)
discardWaiters
()
{
l
.
Lock
()
defer
l
.
Unlock
()
for
i
:=
0
;
i
<
l
.
waiters
;
i
++
{
l
.
Done
()
}
}
}
func
(
l
*
linkGen
)
started
()
bool
{
l
.
RLock
()
defer
l
.
RUnlock
()
return
l
.
generating
}
pagesMutex
.
Lock
()
func
(
l
*
linkGen
)
generateLinks
(
md
Markdown
,
cfg
*
Config
)
{
linksGenerating
=
true
l
.
Lock
()
l
.
generating
=
true
l
.
Unlock
()
fp
:=
filepath
.
Join
(
md
.
Root
,
cfg
.
PathScope
)
fp
:=
filepath
.
Join
(
md
.
Root
,
cfg
.
PathScope
)
cfg
.
Links
=
[]
PageLink
{}
cfg
.
Links
=
[]
PageLink
{}
err
:=
filepath
.
Walk
(
fp
,
func
(
path
string
,
info
os
.
FileInfo
,
err
error
)
error
{
cfg
.
Lock
()
l
.
lastErr
=
filepath
.
Walk
(
fp
,
func
(
path
string
,
info
os
.
FileInfo
,
err
error
)
error
{
for
_
,
ext
:=
range
cfg
.
Extensions
{
for
_
,
ext
:=
range
cfg
.
Extensions
{
if
!
info
.
IsDir
()
&&
strings
.
HasSuffix
(
info
.
Name
(),
ext
)
{
if
!
info
.
IsDir
()
&&
strings
.
HasSuffix
(
info
.
Name
(),
ext
)
{
// Load the file
// Load the file
...
@@ -92,12 +116,46 @@ func GenerateLinks(md Markdown, cfg *Config) error {
...
@@ -92,12 +116,46 @@ func GenerateLinks(md Markdown, cfg *Config) error {
}
}
}
}
// sort by newest date
sort
.
Sort
(
pageLinkSorter
(
cfg
.
Links
))
return
nil
return
nil
})
})
linksGenerating
=
false
// sort by newest date
pagesMutex
.
Unlock
()
sort
.
Sort
(
pageLinkSorter
(
cfg
.
Links
))
return
err
cfg
.
Unlock
()
l
.
Lock
()
l
.
generating
=
false
l
.
Unlock
()
}
type
linkGenerator
struct
{
gens
map
[
*
Config
]
*
linkGen
sync
.
Mutex
}
var
generator
=
linkGenerator
{
gens
:
make
(
map
[
*
Config
]
*
linkGen
)}
// GenerateLinks generates links to all markdown files ordered by newest date.
// This blocks until link generation is done. When called by multiple goroutines,
// the first caller starts the generation and others only wait.
func
GenerateLinks
(
md
Markdown
,
cfg
*
Config
)
error
{
generator
.
Lock
()
// if link generator exists for config and running, wait.
if
g
,
ok
:=
generator
.
gens
[
cfg
];
ok
{
if
g
.
started
()
{
g
.
addWaiter
()
generator
.
Unlock
()
g
.
Wait
()
return
g
.
lastErr
}
}
g
:=
&
linkGen
{}
generator
.
gens
[
cfg
]
=
g
generator
.
Unlock
()
g
.
generateLinks
(
md
,
cfg
)
g
.
discardWaiters
()
return
g
.
lastErr
}
}
middleware/markdown/process.go
View file @
7b29568e
...
@@ -101,9 +101,9 @@ func (md Markdown) processTemplate(c Config, requestPath string, tmpl []byte, me
...
@@ -101,9 +101,9 @@ func (md Markdown) processTemplate(c Config, requestPath string, tmpl []byte, me
Links
:
c
.
Links
,
Links
:
c
.
Links
,
}
}
pagesMutex
.
RLock
()
c
.
RLock
()
err
=
t
.
Execute
(
b
,
mdData
)
err
=
t
.
Execute
(
b
,
mdData
)
pagesMutex
.
RUnlock
()
c
.
RUnlock
()
if
err
!=
nil
{
if
err
!=
nil
{
return
nil
,
err
return
nil
,
err
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment