(w http.ResponseWriter, r *http.Request)
| 1004 | } |
| 1005 | |
| 1006 | func handleConfig(w http.ResponseWriter, r *http.Request) error { |
| 1007 | switch r.Method { |
| 1008 | case http.MethodGet: |
| 1009 | w.Header().Set("Content-Type", "application/json") |
| 1010 | hash := etagHasher() |
| 1011 | |
| 1012 | // Read the config into a buffer instead of writing directly to |
| 1013 | // the response writer, as we want to set the ETag as the header, |
| 1014 | // not the trailer. |
| 1015 | buf := bufferPool.Get().(*bytes.Buffer) |
| 1016 | buf.Reset() |
| 1017 | defer bufferPool.Put(buf) |
| 1018 | |
| 1019 | configWriter := io.MultiWriter(buf, hash) |
| 1020 | err := readConfig(r.URL.Path, configWriter) |
| 1021 | if err != nil { |
| 1022 | return APIError{HTTPStatus: http.StatusBadRequest, Err: err} |
| 1023 | } |
| 1024 | |
| 1025 | // we could consider setting up a sync.Pool for the summed |
| 1026 | // hashes to reduce GC pressure. |
| 1027 | w.Header().Set("Etag", makeEtag(r.URL.Path, hash)) |
| 1028 | _, err = w.Write(buf.Bytes()) |
| 1029 | if err != nil { |
| 1030 | return APIError{HTTPStatus: http.StatusInternalServerError, Err: err} |
| 1031 | } |
| 1032 | |
| 1033 | return nil |
| 1034 | |
| 1035 | case http.MethodPost, |
| 1036 | http.MethodPut, |
| 1037 | http.MethodPatch, |
| 1038 | http.MethodDelete: |
| 1039 | |
| 1040 | // DELETE does not use a body, but the others do |
| 1041 | var body []byte |
| 1042 | if r.Method != http.MethodDelete { |
| 1043 | if ct := r.Header.Get("Content-Type"); !strings.Contains(ct, "/json") { |
| 1044 | return APIError{ |
| 1045 | HTTPStatus: http.StatusBadRequest, |
| 1046 | Err: fmt.Errorf("unacceptable content-type: %v; 'application/json' required", ct), |
| 1047 | } |
| 1048 | } |
| 1049 | |
| 1050 | buf := bufPool.Get().(*bytes.Buffer) |
| 1051 | buf.Reset() |
| 1052 | defer bufPool.Put(buf) |
| 1053 | |
| 1054 | const maxConfigSize = 100 * 1024 * 1024 // 100 MB |
| 1055 | r.Body = http.MaxBytesReader(w, r.Body, maxConfigSize) |
| 1056 | |
| 1057 | _, err := io.Copy(buf, r.Body) |
| 1058 | if err != nil { |
| 1059 | return APIError{ |
| 1060 | HTTPStatus: http.StatusBadRequest, |
| 1061 | Err: fmt.Errorf("reading request body: %v", err), |
| 1062 | } |
| 1063 | } |
nothing calls this directly
no test coverage detected