Skip to content
项目
群组
代码片段
帮助
当前项目
正在载入...
登录 / 注册
切换导航面板
G
go-ipfs
概览
概览
详情
活动
周期分析
版本库
仓库
文件
提交
分支
标签
贡献者
分支图
比较
统计图
问题
0
议题
0
列表
看板
标记
里程碑
合并请求
0
合并请求
0
CI / CD
CI / CD
流水线
作业
日程表
图表
维基
Wiki
代码片段
代码片段
成员
成员
折叠边栏
关闭边栏
活动
图像
聊天
创建新问题
作业
提交
问题看板
Open sidebar
jihao
go-ipfs
Commits
3dfe02aa
提交
3dfe02aa
authored
8月 19, 2015
作者:
Juan Benet
浏览文件
操作
浏览文件
下载
差异文件
Merge pull request #1577 from lgierth/gateway-host-header
gateway: make IPNSHostname work on responses too
上级
d1dd53bd
09d75017
隐藏空白字符变更
内嵌
并排
正在显示
3 个修改的文件
包含
263 行增加
和
20 行删除
+263
-20
gateway_handler.go
core/corehttp/gateway_handler.go
+45
-10
gateway_test.go
core/corehttp/gateway_test.go
+217
-10
ipns_hostname.go
core/corehttp/ipns_hostname.go
+1
-0
没有找到文件。
core/corehttp/gateway_handler.go
浏览文件 @
3dfe02aa
...
...
@@ -90,6 +90,19 @@ func (i *gatewayHandler) getOrHeadHandler(w http.ResponseWriter, r *http.Request
urlPath
:=
r
.
URL
.
Path
// IPNSHostnameOption might have constructed an IPNS path using the Host header.
// In this case, we need the original path for constructing redirects
// and links that match the requested URL.
// For example, http://example.net would become /ipns/example.net, and
// the redirects and links would end up as http://example.net/ipns/example.net
originalUrlPath
:=
urlPath
ipnsHostname
:=
false
hdr
:=
r
.
Header
[
"X-IPNS-Original-Path"
]
if
len
(
hdr
)
>
0
{
originalUrlPath
=
hdr
[
0
]
ipnsHostname
=
true
}
if
i
.
config
.
BlockList
!=
nil
&&
i
.
config
.
BlockList
.
ShouldBlock
(
urlPath
)
{
w
.
WriteHeader
(
http
.
StatusForbidden
)
w
.
Write
([]
byte
(
"403 - Forbidden"
))
...
...
@@ -112,10 +125,17 @@ func (i *gatewayHandler) getOrHeadHandler(w http.ResponseWriter, r *http.Request
w
.
Header
()
.
Set
(
"X-IPFS-Path"
,
urlPath
)
// Suborigin header, sandboxes apps from each other in the browser (even
// though they are served from the same gateway domain). NOTE: This is not
// yet widely supported by browsers.
pathRoot
:=
strings
.
SplitN
(
urlPath
,
"/"
,
4
)[
2
]
w
.
Header
()
.
Set
(
"Suborigin"
,
pathRoot
)
// though they are served from the same gateway domain).
//
// Omited if the path was treated by IPNSHostnameOption(), for example
// a request for http://example.net/ would be changed to /ipns/example.net/,
// which would turn into an incorrect Suborigin: example.net header.
//
// NOTE: This is not yet widely supported by browsers.
if
!
ipnsHostname
{
pathRoot
:=
strings
.
SplitN
(
urlPath
,
"/"
,
4
)[
2
]
w
.
Header
()
.
Set
(
"Suborigin"
,
pathRoot
)
}
dr
,
err
:=
uio
.
NewDagReader
(
ctx
,
nd
,
i
.
node
.
DAG
)
if
err
!=
nil
&&
err
!=
uio
.
ErrIsDir
{
...
...
@@ -150,13 +170,16 @@ func (i *gatewayHandler) getOrHeadHandler(w http.ResponseWriter, r *http.Request
foundIndex
:=
false
for
_
,
link
:=
range
nd
.
Links
{
if
link
.
Name
==
"index.html"
{
log
.
Debugf
(
"found index.html link for %s"
,
urlPath
)
foundIndex
=
true
if
urlPath
[
len
(
urlPath
)
-
1
]
!=
'/'
{
http
.
Redirect
(
w
,
r
,
urlPath
+
"/"
,
302
)
// See comment above where originalUrlPath is declared.
http
.
Redirect
(
w
,
r
,
originalUrlPath
+
"/"
,
302
)
log
.
Debugf
(
"redirect to %s"
,
originalUrlPath
+
"/"
)
return
}
log
.
Debug
(
"found index"
)
foundIndex
=
true
// return index page instead.
nd
,
err
:=
core
.
Resolve
(
ctx
,
i
.
node
,
path
.
Path
(
urlPath
+
"/index.html"
))
if
err
!=
nil
{
...
...
@@ -177,7 +200,8 @@ func (i *gatewayHandler) getOrHeadHandler(w http.ResponseWriter, r *http.Request
break
}
di
:=
directoryItem
{
link
.
Size
,
link
.
Name
,
gopath
.
Join
(
urlPath
,
link
.
Name
)}
// See comment above where originalUrlPath is declared.
di
:=
directoryItem
{
link
.
Size
,
link
.
Name
,
gopath
.
Join
(
originalUrlPath
,
link
.
Name
)}
dirListing
=
append
(
dirListing
,
di
)
}
...
...
@@ -185,7 +209,7 @@ func (i *gatewayHandler) getOrHeadHandler(w http.ResponseWriter, r *http.Request
if
r
.
Method
!=
"HEAD"
{
// construct the correct back link
// https://github.com/ipfs/go-ipfs/issues/1365
var
backLink
string
=
r
.
URL
.
Path
var
backLink
string
=
url
Path
// don't go further up than /ipfs/$hash/
pathSplit
:=
strings
.
Split
(
backLink
,
"/"
)
...
...
@@ -205,9 +229,20 @@ func (i *gatewayHandler) getOrHeadHandler(w http.ResponseWriter, r *http.Request
}
}
// strip /ipfs/$hash from backlink if IPNSHostnameOption touched the path.
if
ipnsHostname
{
backLink
=
"/"
if
len
(
pathSplit
)
>
5
{
// also strip the trailing segment, because it's a backlink
backLinkParts
:=
pathSplit
[
3
:
len
(
pathSplit
)
-
2
]
backLink
+=
strings
.
Join
(
backLinkParts
,
"/"
)
+
"/"
}
}
// See comment above where originalUrlPath is declared.
tplData
:=
listingTemplateData
{
Listing
:
dirListing
,
Path
:
u
rlPath
,
Path
:
originalU
rlPath
,
BackLink
:
backLink
,
}
err
:=
listingTemplate
.
Execute
(
w
,
tplData
)
...
...
core/corehttp/gateway_test.go
浏览文件 @
3dfe02aa
...
...
@@ -37,7 +37,7 @@ func (m mockNamesys) Publish(ctx context.Context, name ci.PrivKey, value path.Pa
return
errors
.
New
(
"not implemented for mockNamesys"
)
}
func
newNodeWithMockNamesys
(
t
*
testing
.
T
,
ns
mockNamesys
)
*
core
.
IpfsNode
{
func
newNodeWithMockNamesys
(
ns
mockNamesys
)
(
*
core
.
IpfsNode
,
error
)
{
c
:=
config
.
Config
{
Identity
:
config
.
Identity
{
PeerID
:
"Qmfoo"
,
// required by offline node
...
...
@@ -49,10 +49,10 @@ func newNodeWithMockNamesys(t *testing.T, ns mockNamesys) *core.IpfsNode {
}
n
,
err
:=
core
.
NewIPFSNode
(
context
.
Background
(),
core
.
Offline
(
r
))
if
err
!=
nil
{
t
.
Fatal
(
err
)
return
nil
,
err
}
n
.
Namesys
=
ns
return
n
return
n
,
nil
}
type
delegatedHandler
struct
{
...
...
@@ -63,21 +63,30 @@ func (dh *delegatedHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
dh
.
Handler
.
ServeHTTP
(
w
,
r
)
}
func
TestGatewayGet
(
t
*
testing
.
T
)
{
t
.
Skip
(
"not sure whats going on here"
)
ns
:=
mockNamesys
{}
n
:=
newNodeWithMockNamesys
(
t
,
ns
)
k
,
err
:=
coreunix
.
Add
(
n
,
strings
.
NewReader
(
"fnord"
))
func
doWithoutRedirect
(
req
*
http
.
Request
)
(
*
http
.
Response
,
error
)
{
tag
:=
"without-redirect"
c
:=
&
http
.
Client
{
CheckRedirect
:
func
(
req
*
http
.
Request
,
via
[]
*
http
.
Request
)
error
{
return
errors
.
New
(
tag
)
},
}
res
,
err
:=
c
.
Do
(
req
)
if
err
!=
nil
&&
!
strings
.
Contains
(
err
.
Error
(),
tag
)
{
return
nil
,
err
}
return
res
,
nil
}
func
newTestServerAndNode
(
t
*
testing
.
T
,
ns
mockNamesys
)
(
*
httptest
.
Server
,
*
core
.
IpfsNode
)
{
n
,
err
:=
newNodeWithMockNamesys
(
ns
)
if
err
!=
nil
{
t
.
Fatal
(
err
)
}
ns
[
"example.com"
]
=
path
.
FromString
(
"/ipfs/"
+
k
)
// need this variable here since we need to construct handler with
// listener, and server with handler. yay cycles.
dh
:=
&
delegatedHandler
{}
ts
:=
httptest
.
NewServer
(
dh
)
defer
ts
.
Close
()
dh
.
Handler
,
err
=
makeHandler
(
n
,
ts
.
Listener
,
...
...
@@ -88,6 +97,20 @@ func TestGatewayGet(t *testing.T) {
t
.
Fatal
(
err
)
}
return
ts
,
n
}
func
TestGatewayGet
(
t
*
testing
.
T
)
{
ns
:=
mockNamesys
{}
ts
,
n
:=
newTestServerAndNode
(
t
,
ns
)
defer
ts
.
Close
()
k
,
err
:=
coreunix
.
Add
(
n
,
strings
.
NewReader
(
"fnord"
))
if
err
!=
nil
{
t
.
Fatal
(
err
)
}
ns
[
"/ipns/example.com"
]
=
path
.
FromString
(
"/ipfs/"
+
k
)
t
.
Log
(
ts
.
URL
)
for
_
,
test
:=
range
[]
struct
{
host
string
...
...
@@ -130,3 +153,187 @@ func TestGatewayGet(t *testing.T) {
}
}
}
func
TestIPNSHostnameRedirect
(
t
*
testing
.
T
)
{
ns
:=
mockNamesys
{}
ts
,
n
:=
newTestServerAndNode
(
t
,
ns
)
t
.
Logf
(
"test server url: %s"
,
ts
.
URL
)
defer
ts
.
Close
()
// create /ipns/example.net/foo/index.html
_
,
dagn1
,
err
:=
coreunix
.
AddWrapped
(
n
,
strings
.
NewReader
(
"_"
),
"_"
)
if
err
!=
nil
{
t
.
Fatal
(
err
)
}
_
,
dagn2
,
err
:=
coreunix
.
AddWrapped
(
n
,
strings
.
NewReader
(
"_"
),
"index.html"
)
if
err
!=
nil
{
t
.
Fatal
(
err
)
}
dagn1
.
AddNodeLink
(
"foo"
,
dagn2
)
if
err
!=
nil
{
t
.
Fatal
(
err
)
}
err
=
n
.
DAG
.
AddRecursive
(
dagn1
)
if
err
!=
nil
{
t
.
Fatal
(
err
)
}
k
,
err
:=
dagn1
.
Key
()
if
err
!=
nil
{
t
.
Fatal
(
err
)
}
t
.
Logf
(
"k: %s
\n
"
,
k
)
ns
[
"/ipns/example.net"
]
=
path
.
FromString
(
"/ipfs/"
+
k
.
String
())
// make request to directory containing index.html
req
,
err
:=
http
.
NewRequest
(
"GET"
,
ts
.
URL
+
"/foo"
,
nil
)
if
err
!=
nil
{
t
.
Fatal
(
err
)
}
req
.
Host
=
"example.net"
res
,
err
:=
doWithoutRedirect
(
req
)
if
err
!=
nil
{
t
.
Fatal
(
err
)
}
// expect 302 redirect to same path, but with trailing slash
if
res
.
StatusCode
!=
302
{
t
.
Errorf
(
"status is %d, expected 302"
,
res
.
StatusCode
)
}
hdr
:=
res
.
Header
[
"Location"
]
if
len
(
hdr
)
<
1
{
t
.
Errorf
(
"location header not present"
)
}
else
if
hdr
[
0
]
!=
"/foo/"
{
t
.
Errorf
(
"location header is %v, expected /foo/"
,
hdr
[
0
])
}
}
func
TestIPNSHostnameBacklinks
(
t
*
testing
.
T
)
{
ns
:=
mockNamesys
{}
ts
,
n
:=
newTestServerAndNode
(
t
,
ns
)
t
.
Logf
(
"test server url: %s"
,
ts
.
URL
)
defer
ts
.
Close
()
// create /ipns/example.net/foo/
_
,
dagn1
,
err
:=
coreunix
.
AddWrapped
(
n
,
strings
.
NewReader
(
"1"
),
"file.txt"
)
if
err
!=
nil
{
t
.
Fatal
(
err
)
}
_
,
dagn2
,
err
:=
coreunix
.
AddWrapped
(
n
,
strings
.
NewReader
(
"2"
),
"file.txt"
)
if
err
!=
nil
{
t
.
Fatal
(
err
)
}
_
,
dagn3
,
err
:=
coreunix
.
AddWrapped
(
n
,
strings
.
NewReader
(
"3"
),
"file.txt"
)
if
err
!=
nil
{
t
.
Fatal
(
err
)
}
dagn2
.
AddNodeLink
(
"bar"
,
dagn3
)
dagn1
.
AddNodeLink
(
"foo"
,
dagn2
)
if
err
!=
nil
{
t
.
Fatal
(
err
)
}
err
=
n
.
DAG
.
AddRecursive
(
dagn1
)
if
err
!=
nil
{
t
.
Fatal
(
err
)
}
k
,
err
:=
dagn1
.
Key
()
if
err
!=
nil
{
t
.
Fatal
(
err
)
}
t
.
Logf
(
"k: %s
\n
"
,
k
)
ns
[
"/ipns/example.net"
]
=
path
.
FromString
(
"/ipfs/"
+
k
.
String
())
// make request to directory listing
req
,
err
:=
http
.
NewRequest
(
"GET"
,
ts
.
URL
+
"/foo/"
,
nil
)
if
err
!=
nil
{
t
.
Fatal
(
err
)
}
req
.
Host
=
"example.net"
res
,
err
:=
doWithoutRedirect
(
req
)
if
err
!=
nil
{
t
.
Fatal
(
err
)
}
// expect correct backlinks
body
,
err
:=
ioutil
.
ReadAll
(
res
.
Body
)
if
err
!=
nil
{
t
.
Fatalf
(
"error reading response: %s"
,
err
)
}
s
:=
string
(
body
)
t
.
Logf
(
"body: %s
\n
"
,
string
(
body
))
if
!
strings
.
Contains
(
s
,
"Index of /foo/"
)
{
t
.
Fatalf
(
"expected a path in directory listing"
)
}
if
!
strings
.
Contains
(
s
,
"<a href=
\"
/
\"
>"
)
{
t
.
Fatalf
(
"expected backlink in directory listing"
)
}
if
!
strings
.
Contains
(
s
,
"<a href=
\"
/foo/file.txt
\"
>"
)
{
t
.
Fatalf
(
"expected file in directory listing"
)
}
// make request to directory listing
req
,
err
=
http
.
NewRequest
(
"GET"
,
ts
.
URL
,
nil
)
if
err
!=
nil
{
t
.
Fatal
(
err
)
}
req
.
Host
=
"example.net"
res
,
err
=
doWithoutRedirect
(
req
)
if
err
!=
nil
{
t
.
Fatal
(
err
)
}
// expect correct backlinks
body
,
err
=
ioutil
.
ReadAll
(
res
.
Body
)
if
err
!=
nil
{
t
.
Fatalf
(
"error reading response: %s"
,
err
)
}
s
=
string
(
body
)
t
.
Logf
(
"body: %s
\n
"
,
string
(
body
))
if
!
strings
.
Contains
(
s
,
"Index of /"
)
{
t
.
Fatalf
(
"expected a path in directory listing"
)
}
if
!
strings
.
Contains
(
s
,
"<a href=
\"
/
\"
>"
)
{
t
.
Fatalf
(
"expected backlink in directory listing"
)
}
if
!
strings
.
Contains
(
s
,
"<a href=
\"
/file.txt
\"
>"
)
{
t
.
Fatalf
(
"expected file in directory listing"
)
}
// make request to directory listing
req
,
err
=
http
.
NewRequest
(
"GET"
,
ts
.
URL
+
"/foo/bar/"
,
nil
)
if
err
!=
nil
{
t
.
Fatal
(
err
)
}
req
.
Host
=
"example.net"
res
,
err
=
doWithoutRedirect
(
req
)
if
err
!=
nil
{
t
.
Fatal
(
err
)
}
// expect correct backlinks
body
,
err
=
ioutil
.
ReadAll
(
res
.
Body
)
if
err
!=
nil
{
t
.
Fatalf
(
"error reading response: %s"
,
err
)
}
s
=
string
(
body
)
t
.
Logf
(
"body: %s
\n
"
,
string
(
body
))
if
!
strings
.
Contains
(
s
,
"Index of /foo/bar/"
)
{
t
.
Fatalf
(
"expected a path in directory listing"
)
}
if
!
strings
.
Contains
(
s
,
"<a href=
\"
/foo/
\"
>"
)
{
t
.
Fatalf
(
"expected backlink in directory listing"
)
}
if
!
strings
.
Contains
(
s
,
"<a href=
\"
/foo/bar/file.txt
\"
>"
)
{
t
.
Fatalf
(
"expected file in directory listing"
)
}
}
core/corehttp/ipns_hostname.go
浏览文件 @
3dfe02aa
...
...
@@ -24,6 +24,7 @@ func IPNSHostnameOption() ServeOption {
if
len
(
host
)
>
0
&&
isd
.
IsDomain
(
host
)
{
name
:=
"/ipns/"
+
host
if
_
,
err
:=
n
.
Namesys
.
Resolve
(
ctx
,
name
);
err
==
nil
{
r
.
Header
[
"X-IPNS-Original-Path"
]
=
[]
string
{
r
.
URL
.
Path
}
r
.
URL
.
Path
=
name
+
r
.
URL
.
Path
}
}
...
...
编写
预览
Markdown
格式
0%
重试
或
添加新文件
添加附件
取消
您添加了
0
人
到此讨论。请谨慎行事。
请先完成此评论的编辑!
取消
请
注册
或者
登录
后发表评论