Skip to content
GitLab
Projects
Groups
Snippets
Help
Loading...
Help
What's new
10
Help
Support
Community forum
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in
Toggle navigation
Open sidebar
dms3
go-dms3
Commits
b299c424
Commit
b299c424
authored
Jan 12, 2015
by
Juan Batiz-Benet
Browse files
Options
Browse Files
Download
Plain Diff
Merge pull request #541 from jbenet/gateway-server
Gateway Server
parents
cfbe4400
2c83cd56
Changes
4
Hide whitespace changes
Inline
Side-by-side
Showing
4 changed files
with
269 additions
and
15 deletions
+269
-15
cmd/ipfs/daemon.go
cmd/ipfs/daemon.go
+55
-12
cmd/ipfs/gatewayHandler.go
cmd/ipfs/gatewayHandler.go
+210
-0
config/config.go
config/config.go
+3
-2
test/sharness/lib/test-lib.sh
test/sharness/lib/test-lib.sh
+1
-1
No files found.
cmd/ipfs/daemon.go
View file @
b299c424
...
...
@@ -24,7 +24,10 @@ const (
ipnsMountKwd
=
"mount-ipns"
// apiAddrKwd = "address-api"
// swarmAddrKwd = "address-swarm"
originEnvKey
=
"API_ORIGIN"
webuiPath
=
"/ipfs/QmTWvqK9dYvqjAMAcCeUun8b45Fwu7wPhEN9B9TsGbkXfJ"
)
var
daemonCmd
=
&
cmds
.
Command
{
...
...
@@ -108,6 +111,16 @@ func daemonFunc(req cmds.Request) (interface{}, error) {
return
nil
,
err
}
var
gatewayMaddr
ma
.
Multiaddr
if
len
(
cfg
.
Addresses
.
Gateway
)
>
0
{
// ignore error for gateway address
// if there is an error (invalid address), then don't run the gateway
gatewayMaddr
,
_
=
ma
.
NewMultiaddr
(
cfg
.
Addresses
.
Gateway
)
if
gatewayMaddr
==
nil
{
log
.
Errorf
(
"Invalid gateway address: %s"
,
cfg
.
Addresses
.
Gateway
)
}
}
// mount if the user provided the --mount flag
mount
,
_
,
err
:=
req
.
Option
(
mountKwd
)
.
Bool
()
if
err
!=
nil
{
...
...
@@ -138,32 +151,54 @@ func daemonFunc(req cmds.Request) (interface{}, error) {
fmt
.
Printf
(
"IPNS mounted at: %s
\n
"
,
nsdir
)
}
if
gatewayMaddr
!=
nil
{
listenAndServeGateway
(
node
,
gatewayMaddr
)
}
return
nil
,
listenAndServeAPI
(
node
,
req
,
apiMaddr
)
}
func
listenAndServeAPI
(
node
*
core
.
IpfsNode
,
req
cmds
.
Request
,
addr
ma
.
Multiaddr
)
error
{
_
,
host
,
err
:=
manet
.
DialArgs
(
addr
)
origin
:=
os
.
Getenv
(
originEnvKey
)
cmdHandler
:=
cmdsHttp
.
NewHandler
(
*
req
.
Context
(),
commands
.
Root
,
origin
)
gateway
,
err
:=
NewGatewayHandler
(
node
)
if
err
!=
nil
{
return
err
}
origin
:=
os
.
Getenv
(
originEnvKey
)
server
:=
manners
.
NewServer
()
mux
:=
http
.
NewServeMux
()
cmdHandler
:=
cmdsHttp
.
NewHandler
(
*
req
.
Context
(),
commands
.
Root
,
origin
)
mux
.
Handle
(
cmdsHttp
.
ApiPath
+
"/"
,
cmdHandler
)
mux
.
Handle
(
"/ipfs/"
,
gateway
)
mux
.
Handle
(
"/webui/"
,
&
redirectHandler
{
webuiPath
})
return
listenAndServe
(
"API"
,
node
,
addr
,
mux
)
}
ifpsHandler
:=
&
ipfsHandler
{
node
}
mux
.
Handle
(
"/ipfs/"
,
ifpsHandler
)
// the gateway also listens on its own address:port in addition to the API listener
func
listenAndServeGateway
(
node
*
core
.
IpfsNode
,
addr
ma
.
Multiaddr
)
error
{
gateway
,
err
:=
NewGatewayHandler
(
node
)
if
err
!=
nil
{
return
err
}
mux
:=
http
.
NewServeMux
()
mux
.
Handle
(
"/ipfs/"
,
gateway
)
return
listenAndServe
(
"gateway"
,
node
,
addr
,
mux
)
}
func
listenAndServe
(
name
string
,
node
*
core
.
IpfsNode
,
addr
ma
.
Multiaddr
,
mux
*
http
.
ServeMux
)
error
{
_
,
host
,
err
:=
manet
.
DialArgs
(
addr
)
if
err
!=
nil
{
return
err
}
server
:=
manners
.
NewServer
()
// if the server exits beforehand
var
serverError
error
serverExited
:=
make
(
chan
struct
{})
go
func
()
{
fmt
.
Printf
(
"
daemon
listening on %s
\n
"
,
addr
)
fmt
.
Printf
(
"
%s server
listening on %s
\n
"
,
name
,
addr
)
serverError
=
server
.
ListenAndServe
(
host
,
mux
)
close
(
serverExited
)
}()
...
...
@@ -174,11 +209,19 @@ func listenAndServeAPI(node *core.IpfsNode, req cmds.Request, addr ma.Multiaddr)
// if node being closed before server exits, close server
case
<-
node
.
Closing
()
:
log
.
Infof
(
"
daemon
at %s terminating..."
,
addr
)
log
.
Infof
(
"
server
at %s terminating..."
,
addr
)
server
.
Shutdown
<-
true
<-
serverExited
// now, DO wait until server exit
s
<-
serverExited
// now, DO wait until server exit
}
log
.
Infof
(
"
daemon
at %s terminated"
,
addr
)
log
.
Infof
(
"
server
at %s terminated"
,
addr
)
return
serverError
}
type
redirectHandler
struct
{
path
string
}
func
(
i
*
redirectHandler
)
ServeHTTP
(
w
http
.
ResponseWriter
,
r
*
http
.
Request
)
{
http
.
Redirect
(
w
,
r
,
i
.
path
,
302
)
}
cmd/ipfs/
ipfs
Handler.go
→
cmd/ipfs/
gateway
Handler.go
View file @
b299c424
package
main
import
(
"html/template"
"io"
"mime"
"net/http"
"strings"
"github.com/jbenet/go-ipfs/Godeps/_workspace/src/code.google.com/p/go.net/context"
mh
"github.com/jbenet/go-ipfs/Godeps/_workspace/src/github.com/jbenet/go-multihash"
...
...
@@ -16,38 +19,70 @@ import (
u
"github.com/jbenet/go-ipfs/util"
)
type
ipfs
interface
{
type
gateway
interface
{
ResolvePath
(
string
)
(
*
dag
.
Node
,
error
)
NewDagFromReader
(
io
.
Reader
)
(
*
dag
.
Node
,
error
)
AddNodeToDAG
(
nd
*
dag
.
Node
)
(
u
.
Key
,
error
)
NewDagReader
(
nd
*
dag
.
Node
)
(
io
.
Reader
,
error
)
}
// ipfsHandler is a HTTP handler that serves IPFS objects (accessible by default at /ipfs/<path>)
// shortcut for templating
type
webHandler
map
[
string
]
interface
{}
// struct for directory listing
type
directoryItem
struct
{
Size
uint64
Name
string
}
// gatewayHandler is a HTTP handler that serves IPFS objects (accessible by default at /ipfs/<path>)
// (it serves requests like GET /ipfs/QmVRzPKPzNtSrEzBFm2UZfxmPAgnaLke4DMcerbsGGSaFe/link)
type
ipfsHandler
struct
{
node
*
core
.
IpfsNode
type
gatewayHandler
struct
{
node
*
core
.
IpfsNode
dirList
*
template
.
Template
}
func
NewGatewayHandler
(
node
*
core
.
IpfsNode
)
(
*
gatewayHandler
,
error
)
{
i
:=
&
gatewayHandler
{
node
:
node
,
}
err
:=
i
.
loadTemplate
()
if
err
!=
nil
{
return
nil
,
err
}
return
i
,
nil
}
// Load the directroy list template
func
(
i
*
gatewayHandler
)
loadTemplate
()
error
{
t
,
err
:=
template
.
New
(
"dir"
)
.
Parse
(
listingTemplate
)
if
err
!=
nil
{
return
err
}
i
.
dirList
=
t
return
nil
}
func
(
i
*
ipfs
Handler
)
ResolvePath
(
path
string
)
(
*
dag
.
Node
,
error
)
{
func
(
i
*
gateway
Handler
)
ResolvePath
(
path
string
)
(
*
dag
.
Node
,
error
)
{
return
i
.
node
.
Resolver
.
ResolvePath
(
path
)
}
func
(
i
*
ipfs
Handler
)
NewDagFromReader
(
r
io
.
Reader
)
(
*
dag
.
Node
,
error
)
{
func
(
i
*
gateway
Handler
)
NewDagFromReader
(
r
io
.
Reader
)
(
*
dag
.
Node
,
error
)
{
return
importer
.
BuildDagFromReader
(
r
,
i
.
node
.
DAG
,
i
.
node
.
Pinning
.
GetManual
(),
chunk
.
DefaultSplitter
)
}
func
(
i
*
ipfs
Handler
)
AddNodeToDAG
(
nd
*
dag
.
Node
)
(
u
.
Key
,
error
)
{
func
(
i
*
gateway
Handler
)
AddNodeToDAG
(
nd
*
dag
.
Node
)
(
u
.
Key
,
error
)
{
return
i
.
node
.
DAG
.
Add
(
nd
)
}
func
(
i
*
ipfs
Handler
)
NewDagReader
(
nd
*
dag
.
Node
)
(
io
.
Reader
,
error
)
{
func
(
i
*
gateway
Handler
)
NewDagReader
(
nd
*
dag
.
Node
)
(
io
.
Reader
,
error
)
{
return
uio
.
NewDagReader
(
nd
,
i
.
node
.
DAG
)
}
func
(
i
*
ipfs
Handler
)
ServeHTTP
(
w
http
.
ResponseWriter
,
r
*
http
.
Request
)
{
func
(
i
*
gateway
Handler
)
ServeHTTP
(
w
http
.
ResponseWriter
,
r
*
http
.
Request
)
{
path
:=
r
.
URL
.
Path
[
5
:
]
log
:=
log
.
Prefix
(
"serving %s"
,
path
)
nd
,
err
:=
i
.
ResolvePath
(
path
)
if
err
!=
nil
{
...
...
@@ -64,19 +99,68 @@ func (i *ipfsHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
return
}
extensionIndex
:=
strings
.
LastIndex
(
path
,
"."
)
if
extensionIndex
!=
-
1
{
extension
:=
path
[
extensionIndex
:
]
mimeType
:=
mime
.
TypeByExtension
(
extension
)
if
len
(
mimeType
)
>
0
{
w
.
Header
()
.
Add
(
"Content-Type"
,
mimeType
)
}
}
dr
,
err
:=
i
.
NewDagReader
(
nd
)
if
err
!=
nil
{
// TODO: return json object containing the tree data if it's a directory (err == ErrIsDir)
w
.
WriteHeader
(
http
.
StatusInternalServerError
)
log
.
Error
(
err
)
w
.
Write
([]
byte
(
err
.
Error
()))
if
err
==
nil
{
io
.
Copy
(
w
,
dr
)
return
}
io
.
Copy
(
w
,
dr
)
if
err
!=
uio
.
ErrIsDir
{
// not a directory and still an error
internalWebError
(
w
,
err
)
return
}
log
.
Debug
(
"listing directory"
)
if
path
[
len
(
path
)
-
1
:
]
!=
"/"
{
log
.
Debug
(
"missing trailing slash, redirect"
)
http
.
Redirect
(
w
,
r
,
"/ipfs/"
+
path
+
"/"
,
307
)
return
}
// storage for directory listing
var
dirListing
[]
directoryItem
// loop through files
for
_
,
link
:=
range
nd
.
Links
{
if
link
.
Name
!=
"index.html"
{
dirListing
=
append
(
dirListing
,
directoryItem
{
link
.
Size
,
link
.
Name
})
continue
}
log
.
Debug
(
"found index"
)
// return index page instead.
nd
,
err
:=
i
.
ResolvePath
(
path
+
"/index.html"
)
if
err
!=
nil
{
internalWebError
(
w
,
err
)
return
}
dr
,
err
:=
i
.
NewDagReader
(
nd
)
if
err
!=
nil
{
internalWebError
(
w
,
err
)
return
}
// write to request
io
.
Copy
(
w
,
dr
)
}
// template and return directory listing
hndlr
:=
webHandler
{
"listing"
:
dirListing
,
"path"
:
path
}
if
err
:=
i
.
dirList
.
Execute
(
w
,
hndlr
);
err
!=
nil
{
internalWebError
(
w
,
err
)
return
}
}
func
(
i
*
ipfs
Handler
)
postHandler
(
w
http
.
ResponseWriter
,
r
*
http
.
Request
)
{
func
(
i
*
gateway
Handler
)
postHandler
(
w
http
.
ResponseWriter
,
r
*
http
.
Request
)
{
nd
,
err
:=
i
.
NewDagFromReader
(
r
.
Body
)
if
err
!=
nil
{
w
.
WriteHeader
(
http
.
StatusInternalServerError
)
...
...
@@ -97,3 +181,30 @@ func (i *ipfsHandler) postHandler(w http.ResponseWriter, r *http.Request) {
w
.
WriteHeader
(
http
.
StatusCreated
)
w
.
Write
([]
byte
(
mh
.
Multihash
(
k
)
.
B58String
()))
}
// return a 500 error and log
func
internalWebError
(
w
http
.
ResponseWriter
,
err
error
)
{
w
.
WriteHeader
(
http
.
StatusInternalServerError
)
w
.
Write
([]
byte
(
err
.
Error
()))
log
.
Error
(
"%s"
,
err
)
}
// Directory listing template
var
listingTemplate
=
`
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<title>{{ .path }}</title>
</head>
<body>
<h2>Index of {{ .path }}</h2>
<ul>
<li><a href="./..">..</a></li>
{{ range $item := .listing }}
<li><a href="./{{ $item.Name }}">{{ $item.Name }}</a> - {{ $item.Size }} bytes</li>
{{ end }}
</ul>
</body>
</html>
`
config/config.go
View file @
b299c424
...
...
@@ -40,8 +40,9 @@ type Datastore struct {
// Addresses stores the (string) multiaddr addresses for the node.
type
Addresses
struct
{
Swarm
[]
string
// addresses for the swarm network
API
string
// address for the local API (RPC)
Swarm
[]
string
// addresses for the swarm network
API
string
// address for the local API (RPC)
Gateway
string
// address to listen on for IPFS HTTP object gateway
}
// Mounts stores the (string) mount points
...
...
test/sharness/lib/test-lib.sh
View file @
b299c424
...
...
@@ -88,7 +88,7 @@ test_launch_ipfs_daemon() {
test_expect_success FUSE
"'ipfs daemon' output looks good"
'
IPFS_PID=$! &&
echo "
daemon
listening on /ip4/127.0.0.1/tcp/5001" >expected &&
echo "
API server
listening on /ip4/127.0.0.1/tcp/5001" >expected &&
test_cmp_repeat_10_sec expected actual ||
fsh cat daemon_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