Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Support
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
G
gitlab-workhorse
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
iv
gitlab-workhorse
Commits
208403df
Commit
208403df
authored
Dec 18, 2015
by
Jacob Vosmaer
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Forgot to add api directory
parent
9fd59b22
Changes
1
Show whitespace changes
Inline
Side-by-side
Showing
1 changed file
with
150 additions
and
0 deletions
+150
-0
internal/api/api.go
internal/api/api.go
+150
-0
No files found.
internal/api/api.go
0 → 100644
View file @
208403df
package
api
import
(
"../helper"
"../proxy"
"encoding/json"
"fmt"
"io"
"io/ioutil"
"net/http"
"net/url"
"strings"
)
type
API
struct
{
*
http
.
Client
*
url
.
URL
Version
string
}
type
HandleFunc
func
(
http
.
ResponseWriter
,
*
http
.
Request
,
*
Response
)
type
Response
struct
{
// GL_ID is an environment variable used by gitlab-shell hooks during 'git
// push' and 'git pull'
GL_ID
string
// RepoPath is the full path on disk to the Git repository the request is
// about
RepoPath
string
// ArchivePath is the full path where we should find/create a cached copy
// of a requested archive
ArchivePath
string
// ArchivePrefix is used to put extracted archive contents in a
// subdirectory
ArchivePrefix
string
// CommitId is used do prevent race conditions between the 'time of check'
// in the GitLab Rails app and the 'time of use' in gitlab-workhorse.
CommitId
string
// StoreLFSPath is provided by the GitLab Rails application
// to mark where the tmp file should be placed
StoreLFSPath
string
// LFS object id
LfsOid
string
// LFS object size
LfsSize
int64
// TmpPath is the path where we should store temporary files
// This is set by authorization middleware
TempPath
string
}
func
(
api
*
API
)
newRequest
(
r
*
http
.
Request
,
body
io
.
Reader
,
suffix
string
)
(
*
http
.
Request
,
error
)
{
url
:=
*
api
.
URL
url
.
Path
=
r
.
URL
.
RequestURI
()
+
suffix
authReq
:=
&
http
.
Request
{
Method
:
r
.
Method
,
URL
:
&
url
,
Header
:
proxy
.
HeaderClone
(
r
.
Header
),
}
if
body
!=
nil
{
authReq
.
Body
=
ioutil
.
NopCloser
(
body
)
}
// Clean some headers when issuing a new request without body
if
body
==
nil
{
authReq
.
Header
.
Del
(
"Content-Type"
)
authReq
.
Header
.
Del
(
"Content-Encoding"
)
authReq
.
Header
.
Del
(
"Content-Length"
)
authReq
.
Header
.
Del
(
"Content-Disposition"
)
authReq
.
Header
.
Del
(
"Accept-Encoding"
)
// Hop-by-hop headers. These are removed when sent to the backend.
// http://www.w3.org/Protocols/rfc2616/rfc2616-sec13.html
authReq
.
Header
.
Del
(
"Transfer-Encoding"
)
authReq
.
Header
.
Del
(
"Connection"
)
authReq
.
Header
.
Del
(
"Keep-Alive"
)
authReq
.
Header
.
Del
(
"Proxy-Authenticate"
)
authReq
.
Header
.
Del
(
"Proxy-Authorization"
)
authReq
.
Header
.
Del
(
"Te"
)
authReq
.
Header
.
Del
(
"Trailers"
)
authReq
.
Header
.
Del
(
"Upgrade"
)
}
// Also forward the Host header, which is excluded from the Header map by the http libary.
// This allows the Host header received by the backend to be consistent with other
// requests not going through gitlab-workhorse.
authReq
.
Host
=
r
.
Host
// Set a custom header for the request. This can be used in some
// configurations (Passenger) to solve auth request routing problems.
authReq
.
Header
.
Set
(
"Gitlab-Workhorse"
,
api
.
Version
)
return
authReq
,
nil
}
func
(
api
*
API
)
PreAuthorizeHandler
(
h
HandleFunc
,
suffix
string
)
http
.
HandlerFunc
{
return
func
(
w
http
.
ResponseWriter
,
r
*
http
.
Request
)
{
authReq
,
err
:=
api
.
newRequest
(
r
,
nil
,
suffix
)
if
err
!=
nil
{
helper
.
Fail500
(
w
,
fmt
.
Errorf
(
"preAuthorizeHandler: newUpstreamRequest: %v"
,
err
))
return
}
authResponse
,
err
:=
api
.
Do
(
authReq
)
if
err
!=
nil
{
helper
.
Fail500
(
w
,
fmt
.
Errorf
(
"preAuthorizeHandler: do %v: %v"
,
authReq
.
URL
.
Path
,
err
))
return
}
defer
authResponse
.
Body
.
Close
()
if
authResponse
.
StatusCode
!=
200
{
// The Git request is not allowed by the backend. Maybe the
// client needs to send HTTP Basic credentials. Forward the
// response from the auth backend to our client. This includes
// the 'WWW-Authenticate' header that acts as a hint that
// Basic auth credentials are needed.
for
k
,
v
:=
range
authResponse
.
Header
{
// Accomodate broken clients that do case-sensitive header lookup
if
k
==
"Www-Authenticate"
{
w
.
Header
()[
"WWW-Authenticate"
]
=
v
}
else
{
w
.
Header
()[
k
]
=
v
}
}
w
.
WriteHeader
(
authResponse
.
StatusCode
)
io
.
Copy
(
w
,
authResponse
.
Body
)
return
}
a
:=
&
Response
{}
// The auth backend validated the client request and told us additional
// request metadata. We must extract this information from the auth
// response body.
if
err
:=
json
.
NewDecoder
(
authResponse
.
Body
)
.
Decode
(
a
);
err
!=
nil
{
helper
.
Fail500
(
w
,
fmt
.
Errorf
(
"preAuthorizeHandler: decode authorization response: %v"
,
err
))
return
}
// Don't hog a TCP connection in CLOSE_WAIT, we can already close it now
authResponse
.
Body
.
Close
()
// Negotiate authentication (Kerberos) may need to return a WWW-Authenticate
// header to the client even in case of success as per RFC4559.
for
k
,
v
:=
range
authResponse
.
Header
{
// Case-insensitive comparison as per RFC7230
if
strings
.
EqualFold
(
k
,
"WWW-Authenticate"
)
{
w
.
Header
()[
k
]
=
v
}
}
h
(
w
,
r
,
a
)
}
}
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