Commit 3ed8cce1 authored by Geoff Simmons's avatar Geoff Simmons

REST API: validate conditional requests for /v1/pems/{namespace}/{name}

parent 49b55fbb
......@@ -286,7 +286,6 @@ func (h *pemsHndlr) pemInfo(
now time.Time,
) {
// XXX check Accept
// XXX I-M-S and I-N-M
info, found, err := h.files.GetFileInfo(ns, name, uid, version)
if !found {
h.errorResponse(resp, req, now, http.StatusNotFound,
......@@ -298,13 +297,48 @@ func (h *pemsHndlr) pemInfo(
errPemsReadErr, err)
return
}
resp.Header().Set("ETag",
info.K8sSecret.UID+"/"+info.K8sSecret.Version)
resp.Header().Set("Last-Modified",
info.Meta.ModTime.UTC().Format(http.TimeFormat))
inm := req.Header.Get("If-None-Match")
h.log.Info("If-None-Match: ", inm)
h.log.Info("info.K8sSecret.UID: ", info.K8sSecret.UID)
h.log.Info("info.K8sSecret.Version: ", info.K8sSecret.Version)
if inm != "" {
tags := strings.Split(strings.TrimPrefix(inm, "W/"), "/")
h.log.Infof("tags: %+v", tags)
if len(tags) == 2 && tags[0] == info.K8sSecret.UID &&
tags[1] == info.K8sSecret.Version {
resp.Header().Del("Content-Length")
resp.WriteHeader(http.StatusNotModified)
reqLog(h.log, req, now, http.StatusNotModified, 0)
return
}
}
ims := req.Header.Get("If-Modified-Since")
if ims != "" {
since, err := time.Parse(http.TimeFormat, ims)
if err != nil {
h.log.Errorf("%s %s: cannot parse If-Modified-Since "+
"\"%s\": %v", req.Method, req.RequestURI, ims,
err)
} else if !info.Meta.ModTime.UTC().Truncate(time.Second).
After(since.UTC()) {
resp.Header().Del("Content-Length")
resp.WriteHeader(http.StatusNotModified)
reqLog(h.log, req, now, http.StatusNotModified, 0)
return
}
}
jsonBytes, err := json.Marshal(info)
if err != nil {
h.errorResponse(resp, req, now, http.StatusInternalServerError,
errPemsJSONMarshal, err)
return
}
// XXX LastModified and ETag
resp.Header().Set("Content-Type", jsonContentType)
resp.Header().Set("Content-Length", strconv.Itoa(len(jsonBytes)))
n := 0
......
......@@ -757,3 +757,126 @@ func TestGetPem(t *testing.T) {
"got %s want /log/errors/N", problem.Instance)
}
}
func TestValidatePem(t *testing.T) {
client := fake.NewSimpleClientset()
lister := setupSecretLister(client)
getter := crt.NewGetter(lister)
files, err := pem.NewFiles(basedir, -1, getter)
if err != nil {
t.Fatalf("NewFiles(): %v", err)
}
files.Files["ns1/cafe"] = cafeFile
hndlr := &pemsHndlr{
log: &logrus.Logger{Out: ioutil.Discard},
files: files,
crtGetter: getter,
}
req := httptest.NewRequest(http.MethodGet, "/v1/pems/ns1/cafe", nil)
rr := httptest.NewRecorder()
hndlr.ServeHTTP(rr, req)
if rr.Code != http.StatusOK {
t.Errorf("GET /v1/pems/ns1/cafe status: got %d want %d",
rr.Code, http.StatusOK)
}
tag := cafeFile.UID + "/" + cafeFile.ResourceVersion
if rr.Header().Get("ETag") != tag {
t.Errorf("GET /v1/pems/ns1/cafe ETag: got %s want %s",
rr.Header().Get("ETag"), tag)
}
lmTime, err := time.Parse(http.TimeFormat,
rr.Header().Get("Last-Modified"))
if err != nil {
t.Fatalf("GET /v1/pems/ns1/cafe Last-Modified: %v", err)
}
if !lmTime.Equal(cafeFile.ModTime) {
t.Errorf("GET /v1/pems/ns1/cafe Last-Modified: got %s want %s",
rr.Header().Get("Last-Modified"),
cafeFile.ModTime.Format(http.TimeFormat))
}
req = httptest.NewRequest(http.MethodGet, "/v1/pems/ns1/cafe", nil)
rr = httptest.NewRecorder()
req.Header.Set("If-None-Match", tag)
hndlr.ServeHTTP(rr, req)
if rr.Code != http.StatusNotModified {
t.Errorf("GET /v1/pems/ns1/cafe status: got %d want %d",
rr.Code, http.StatusNotModified)
}
if rr.Body.Len() > 0 {
t.Errorf("GET /v1/pems/ns1/cafe body len: got %d want 0",
rr.Body.Len())
}
if rr.Header().Get("Content-Type") != "" {
t.Errorf("GET /v1/pems/ns1/cafe Content-Type: got %s want empty",
rr.Header().Get("Content-Type"))
}
if rr.Header().Get("Content-Length") != "" {
t.Errorf("GET /v1/pems/ns1/cafe Content-Length: "+
"got %s want empty", rr.Header().Get("Content-Length"))
}
req = httptest.NewRequest(http.MethodGet, "/v1/pems/ns1/cafe", nil)
rr = httptest.NewRecorder()
req.Header.Set("If-None-Match",
"d18974c5-94d7-4e04-b2af-6e9274ad46d8/0815")
hndlr.ServeHTTP(rr, req)
if rr.Code != http.StatusOK {
t.Errorf("GET /v1/pems/ns1/cafe status: got %d want %d",
rr.Code, http.StatusOK)
}
if rr.Body.Len() == 0 {
t.Error("GET /v1/pems/ns1/cafe body len: got 0 want > 0")
}
req = httptest.NewRequest(http.MethodGet, "/v1/pems/ns1/cafe", nil)
rr = httptest.NewRecorder()
req.Header.Set("If-Modified-Since",
cafeFile.ModTime.Format(http.TimeFormat))
hndlr.ServeHTTP(rr, req)
if rr.Code != http.StatusNotModified {
t.Errorf("GET /v1/pems/ns1/cafe status: got %d want %d",
rr.Code, http.StatusNotModified)
}
if rr.Body.Len() > 0 {
t.Errorf("GET /v1/pems/ns1/cafe body len: got %d want 0",
rr.Body.Len())
}
if rr.Header().Get("Content-Type") != "" {
t.Errorf("GET /v1/pems/ns1/cafe Content-Type: got %s want empty",
rr.Header().Get("Content-Type"))
}
if rr.Header().Get("Content-Length") != "" {
t.Errorf("GET /v1/pems/ns1/cafe Content-Length: "+
"got %s want empty", rr.Header().Get("Content-Length"))
}
req = httptest.NewRequest(http.MethodGet, "/v1/pems/ns1/cafe", nil)
rr = httptest.NewRecorder()
req.Header.Set("If-Modified-Since",
cafeFile.ModTime.Add(time.Second).Format(http.TimeFormat))
hndlr.ServeHTTP(rr, req)
if rr.Code != http.StatusNotModified {
t.Errorf("GET /v1/pems/ns1/cafe status: got %d want %d",
rr.Code, http.StatusNotModified)
}
if rr.Body.Len() > 0 {
t.Errorf("GET /v1/pems/ns1/cafe body len: got %d want 0",
rr.Body.Len())
}
req = httptest.NewRequest(http.MethodGet, "/v1/pems/ns1/cafe", nil)
rr = httptest.NewRecorder()
req.Header.Set("If-Modified-Since",
cafeFile.ModTime.Add(-1*time.Second).Format(http.TimeFormat))
hndlr.ServeHTTP(rr, req)
if rr.Code != http.StatusOK {
t.Errorf("GET /v1/pems/ns1/cafe status: got %d want %d",
rr.Code, http.StatusOK)
}
if rr.Body.Len() == 0 {
t.Error("GET /v1/pems/ns1/cafe body len: got 0 want > 0")
}
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment