Skip to content
Projects
Groups
Snippets
Help
This project
Loading...
Sign in / Register
Toggle navigation
K
k3s
Project
Project
Details
Activity
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Board
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Registry
Registry
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
Jacklull
k3s
Commits
32694a77
Commit
32694a77
authored
Feb 24, 2015
by
Vish Kannan
Browse files
Options
Browse Files
Download
Plain Diff
Merge pull request #4778 from lavalamp/fix7
Construct path correctly in proxy
parents
0b15f2ff
ec58e6d7
Hide whitespace changes
Inline
Side-by-side
Showing
3 changed files
with
87 additions
and
55 deletions
+87
-55
handlers.go
pkg/apiserver/handlers.go
+22
-3
handlers_test.go
pkg/apiserver/handlers_test.go
+4
-0
proxy.go
pkg/apiserver/proxy.go
+61
-52
No files found.
pkg/apiserver/handlers.go
View file @
32694a77
...
@@ -19,6 +19,7 @@ package apiserver
...
@@ -19,6 +19,7 @@ package apiserver
import
(
import
(
"fmt"
"fmt"
"net/http"
"net/http"
"path"
"regexp"
"regexp"
"runtime/debug"
"runtime/debug"
"strings"
"strings"
...
@@ -214,8 +215,22 @@ type APIRequestInfo struct {
...
@@ -214,8 +215,22 @@ type APIRequestInfo struct {
Kind
string
Kind
string
// Name is empty for some verbs, but if the request directly indicates a name (not in body content) then this field is filled in.
// Name is empty for some verbs, but if the request directly indicates a name (not in body content) then this field is filled in.
Name
string
Name
string
// Parts are the path parts for the request
relative to
/{resource}/{name}
// Parts are the path parts for the request
, always starting with
/{resource}/{name}
Parts
[]
string
Parts
[]
string
// Raw is the unparsed form of everything other than parts.
// Raw + Parts = complete URL path
Raw
[]
string
}
// URLPath returns the URL path for this request, including /{resource}/{name} if present but nothing
// following that.
func
(
info
APIRequestInfo
)
URLPath
()
string
{
p
:=
info
.
Parts
if
n
:=
len
(
p
);
n
>
2
{
// Only take resource and name
p
=
p
[
:
2
]
}
return
path
.
Join
(
"/"
,
path
.
Join
(
info
.
Raw
...
),
path
.
Join
(
p
...
))
}
}
type
APIRequestInfoResolver
struct
{
type
APIRequestInfoResolver
struct
{
...
@@ -247,9 +262,11 @@ type APIRequestInfoResolver struct {
...
@@ -247,9 +262,11 @@ type APIRequestInfoResolver struct {
// /api/{version}/*
// /api/{version}/*
// /api/{version}/*
// /api/{version}/*
func
(
r
*
APIRequestInfoResolver
)
GetAPIRequestInfo
(
req
*
http
.
Request
)
(
APIRequestInfo
,
error
)
{
func
(
r
*
APIRequestInfoResolver
)
GetAPIRequestInfo
(
req
*
http
.
Request
)
(
APIRequestInfo
,
error
)
{
requestInfo
:=
APIRequestInfo
{}
requestInfo
:=
APIRequestInfo
{
Raw
:
splitPath
(
req
.
URL
.
Path
),
}
currentParts
:=
splitPath
(
req
.
URL
.
Path
)
currentParts
:=
requestInfo
.
Raw
if
len
(
currentParts
)
<
1
{
if
len
(
currentParts
)
<
1
{
return
requestInfo
,
fmt
.
Errorf
(
"Unable to determine kind and namespace from an empty URL path"
)
return
requestInfo
,
fmt
.
Errorf
(
"Unable to determine kind and namespace from an empty URL path"
)
}
}
...
@@ -322,6 +339,8 @@ func (r *APIRequestInfoResolver) GetAPIRequestInfo(req *http.Request) (APIReques
...
@@ -322,6 +339,8 @@ func (r *APIRequestInfoResolver) GetAPIRequestInfo(req *http.Request) (APIReques
// parsing successful, so we now know the proper value for .Parts
// parsing successful, so we now know the proper value for .Parts
requestInfo
.
Parts
=
currentParts
requestInfo
.
Parts
=
currentParts
// Raw should have everything not in Parts
requestInfo
.
Raw
=
requestInfo
.
Raw
[
:
len
(
requestInfo
.
Raw
)
-
len
(
currentParts
)]
// if there's another part remaining after the kind, then that's the resource name
// if there's another part remaining after the kind, then that's the resource name
if
len
(
requestInfo
.
Parts
)
>=
2
{
if
len
(
requestInfo
.
Parts
)
>=
2
{
...
...
pkg/apiserver/handlers_test.go
View file @
32694a77
...
@@ -20,6 +20,7 @@ import (
...
@@ -20,6 +20,7 @@ import (
"net/http"
"net/http"
"net/http/httptest"
"net/http/httptest"
"reflect"
"reflect"
"strings"
"testing"
"testing"
"github.com/GoogleCloudPlatform/kubernetes/pkg/api"
"github.com/GoogleCloudPlatform/kubernetes/pkg/api"
...
@@ -142,6 +143,9 @@ func TestGetAPIRequestInfo(t *testing.T) {
...
@@ -142,6 +143,9 @@ func TestGetAPIRequestInfo(t *testing.T) {
if
!
reflect
.
DeepEqual
(
successCase
.
expectedParts
,
apiRequestInfo
.
Parts
)
{
if
!
reflect
.
DeepEqual
(
successCase
.
expectedParts
,
apiRequestInfo
.
Parts
)
{
t
.
Errorf
(
"Unexpected parts for url: %s, expected: %v, actual: %v"
,
successCase
.
url
,
successCase
.
expectedParts
,
apiRequestInfo
.
Parts
)
t
.
Errorf
(
"Unexpected parts for url: %s, expected: %v, actual: %v"
,
successCase
.
url
,
successCase
.
expectedParts
,
apiRequestInfo
.
Parts
)
}
}
if
e
,
a
:=
strings
.
Split
(
successCase
.
url
,
"?"
)[
0
],
apiRequestInfo
.
URLPath
();
e
!=
a
{
t
.
Errorf
(
"Expected %v, got %v"
,
e
,
a
)
}
}
}
errorCases
:=
map
[
string
]
string
{
errorCases
:=
map
[
string
]
string
{
...
...
pkg/apiserver/proxy.go
View file @
32694a77
...
@@ -182,64 +182,73 @@ func (r *ProxyHandler) ServeHTTP(w http.ResponseWriter, req *http.Request) {
...
@@ -182,64 +182,73 @@ func (r *ProxyHandler) ServeHTTP(w http.ResponseWriter, req *http.Request) {
// TODO convert this entire proxy to an UpgradeAwareProxy similar to
// TODO convert this entire proxy to an UpgradeAwareProxy similar to
// https://github.com/openshift/origin/blob/master/pkg/util/httpproxy/upgradeawareproxy.go.
// https://github.com/openshift/origin/blob/master/pkg/util/httpproxy/upgradeawareproxy.go.
// That proxy needs to be modified to support multiple backends, not just 1.
// That proxy needs to be modified to support multiple backends, not just 1.
if
r
.
tryUpgrade
(
w
,
req
,
newReq
,
destURL
)
{
return
}
proxy
:=
httputil
.
NewSingleHostReverseProxy
(
&
url
.
URL
{
Scheme
:
"http"
,
Host
:
destURL
.
Host
})
proxy
.
Transport
=
&
proxyTransport
{
proxyScheme
:
req
.
URL
.
Scheme
,
proxyHost
:
req
.
URL
.
Host
,
proxyPathPrepend
:
requestInfo
.
URLPath
(),
}
proxy
.
FlushInterval
=
200
*
time
.
Millisecond
proxy
.
ServeHTTP
(
w
,
newReq
)
}
// tryUpgrade returns true if the request was handled.
func
(
r
*
ProxyHandler
)
tryUpgrade
(
w
http
.
ResponseWriter
,
req
,
newReq
*
http
.
Request
,
destURL
*
url
.
URL
)
bool
{
connectionHeader
:=
strings
.
ToLower
(
req
.
Header
.
Get
(
httpstream
.
HeaderConnection
))
connectionHeader
:=
strings
.
ToLower
(
req
.
Header
.
Get
(
httpstream
.
HeaderConnection
))
if
strings
.
Contains
(
connectionHeader
,
strings
.
ToLower
(
httpstream
.
HeaderUpgrade
))
&&
len
(
req
.
Header
.
Get
(
httpstream
.
HeaderUpgrade
))
>
0
{
if
!
strings
.
Contains
(
connectionHeader
,
strings
.
ToLower
(
httpstream
.
HeaderUpgrade
))
||
len
(
req
.
Header
.
Get
(
httpstream
.
HeaderUpgrade
))
==
0
{
//TODO support TLS? Doesn't look like proxyTransport does anything special ...
return
false
dialAddr
:=
netutil
.
CanonicalAddr
(
destURL
)
}
backendConn
,
err
:=
net
.
Dial
(
"tcp"
,
dialAddr
)
//TODO support TLS? Doesn't look like proxyTransport does anything special ...
if
err
!=
nil
{
dialAddr
:=
netutil
.
CanonicalAddr
(
destURL
)
status
:=
errToAPIStatus
(
err
)
backendConn
,
err
:=
net
.
Dial
(
"tcp"
,
dialAddr
)
writeJSON
(
status
.
Code
,
r
.
codec
,
status
,
w
)
if
err
!=
nil
{
return
status
:=
errToAPIStatus
(
err
)
}
writeJSON
(
status
.
Code
,
r
.
codec
,
status
,
w
)
defer
backendConn
.
Close
()
return
true
}
defer
backendConn
.
Close
()
// TODO should we use _ (a bufio.ReadWriter) instead of requestHijackedConn
// TODO should we use _ (a bufio.ReadWriter) instead of requestHijackedConn
// when copying between the client and the backend? Docker doesn't when they
// when copying between the client and the backend? Docker doesn't when they
// hijack, just for reference...
// hijack, just for reference...
requestHijackedConn
,
_
,
err
:=
w
.
(
http
.
Hijacker
)
.
Hijack
()
requestHijackedConn
,
_
,
err
:=
w
.
(
http
.
Hijacker
)
.
Hijack
()
if
err
!=
nil
{
if
err
!=
nil
{
status
:=
errToAPIStatus
(
err
)
status
:=
errToAPIStatus
(
err
)
writeJSON
(
status
.
Code
,
r
.
codec
,
status
,
w
)
writeJSON
(
status
.
Code
,
r
.
codec
,
status
,
w
)
return
return
true
}
}
defer
requestHijackedConn
.
Close
()
defer
requestHijackedConn
.
Close
()
if
err
=
newReq
.
Write
(
backendConn
);
err
!=
nil
{
if
err
=
newReq
.
Write
(
backendConn
);
err
!=
nil
{
status
:=
errToAPIStatus
(
err
)
status
:=
errToAPIStatus
(
err
)
writeJSON
(
status
.
Code
,
r
.
codec
,
status
,
w
)
writeJSON
(
status
.
Code
,
r
.
codec
,
status
,
w
)
return
return
true
}
done
:=
make
(
chan
struct
{},
2
)
go
func
()
{
_
,
err
:=
io
.
Copy
(
backendConn
,
requestHijackedConn
)
if
err
!=
nil
&&
!
strings
.
Contains
(
err
.
Error
(),
"use of closed network connection"
)
{
glog
.
Errorf
(
"Error proxying data from client to backend: %v"
,
err
)
}
}
done
<-
struct
{}{}
}()
done
:=
make
(
chan
struct
{},
2
)
go
func
()
{
_
,
err
:=
io
.
Copy
(
requestHijackedConn
,
backendConn
)
go
func
()
{
if
err
!=
nil
&&
!
strings
.
Contains
(
err
.
Error
(),
"use of closed network connection"
)
{
_
,
err
:=
io
.
Copy
(
backendConn
,
requestHijackedConn
)
glog
.
Errorf
(
"Error proxying data from backend to client: %v"
,
err
)
if
err
!=
nil
&&
!
strings
.
Contains
(
err
.
Error
(),
"use of closed network connection"
)
{
glog
.
Errorf
(
"Error proxying data from client to backend: %v"
,
err
)
}
done
<-
struct
{}{}
}()
go
func
()
{
_
,
err
:=
io
.
Copy
(
requestHijackedConn
,
backendConn
)
if
err
!=
nil
&&
!
strings
.
Contains
(
err
.
Error
(),
"use of closed network connection"
)
{
glog
.
Errorf
(
"Error proxying data from backend to client: %v"
,
err
)
}
done
<-
struct
{}{}
}()
<-
done
}
else
{
proxy
:=
httputil
.
NewSingleHostReverseProxy
(
&
url
.
URL
{
Scheme
:
"http"
,
Host
:
destURL
.
Host
})
proxy
.
Transport
=
&
proxyTransport
{
proxyScheme
:
req
.
URL
.
Scheme
,
proxyHost
:
req
.
URL
.
Host
,
proxyPathPrepend
:
path
.
Join
(
r
.
prefix
,
"ns"
,
namespace
,
resource
,
id
),
}
}
proxy
.
FlushInterval
=
200
*
time
.
Millisecond
done
<-
struct
{}{}
proxy
.
ServeHTTP
(
w
,
newReq
)
}()
}
<-
done
return
true
}
}
type
proxyTransport
struct
{
type
proxyTransport
struct
{
...
...
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