github.com/openshift-online/ocm-sdk-go@v0.1.473/internal/check_content_type.go (about) 1 /* 2 Copyright (c) 2021 Red Hat, Inc. 3 4 Licensed under the Apache License, Version 2.0 (the "License"); 5 you may not use this file except in compliance with the License. 6 You may obtain a copy of the License at 7 8 http://www.apache.org/licenses/LICENSE-2.0 9 10 Unless required by applicable law or agreed to in writing, software 11 distributed under the License is distributed on an "AS IS" BASIS, 12 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 See the License for the specific language governing permissions and 14 limitations under the License. 15 */ 16 17 // This file contains the functions used to check content types. 18 19 package internal 20 21 import ( 22 "fmt" 23 "html" 24 "io" 25 "mime" 26 "net/http" 27 "regexp" 28 "strings" 29 30 "github.com/microcosm-cc/bluemonday" 31 ) 32 33 var wsRegex = regexp.MustCompile(`\s+`) 34 35 // CheckContentType checks that the content type of the given response is JSON. Note that if the 36 // content type isn't JSON this method will consume the complete body in order to generate an error 37 // message containing a summary of the content. 38 func CheckContentType(response *http.Response) error { 39 var err error 40 var mediaType string 41 if response.StatusCode == http.StatusNoContent { 42 return nil 43 } 44 contentType := response.Header.Get("Content-Type") 45 if contentType != "" { 46 mediaType, _, err = mime.ParseMediaType(contentType) 47 if err != nil { 48 return err 49 } 50 } else { 51 mediaType = contentType 52 } 53 if !strings.EqualFold(mediaType, "application/json") { 54 var summary string 55 summary, err = contentSummary(mediaType, response) 56 if err != nil { 57 return fmt.Errorf( 58 "expected response content type 'application/json' but received "+ 59 "'%s' and couldn't obtain content summary: %w", 60 mediaType, err, 61 ) 62 } 63 return fmt.Errorf( 64 "expected response content type 'application/json' but received '%s' and "+ 65 "content '%s'", 66 mediaType, summary, 67 ) 68 } 69 return nil 70 } 71 72 // contentSummary reads the body of the given response and returns a summary it. The summary will 73 // be the complete body if it isn't too log. If it is too long then the summary will be the 74 // beginning of the content followed by ellipsis. 75 func contentSummary(mediaType string, response *http.Response) (summary string, err error) { 76 var body []byte 77 body, err = io.ReadAll(response.Body) 78 if err != nil { 79 return 80 } 81 limit := 250 82 runes := []rune(string(body)) 83 if strings.EqualFold(mediaType, "text/html") && len(runes) > limit { 84 content := html.UnescapeString(bluemonday.StrictPolicy().Sanitize(string(body))) 85 content = wsRegex.ReplaceAllString(strings.TrimSpace(content), " ") 86 runes = []rune(content) 87 } 88 if len(runes) > limit { 89 summary = fmt.Sprintf("%s...", string(runes[:limit])) 90 } else { 91 summary = string(runes) 92 } 93 return 94 }