mirror of
https://github.com/gohugoio/hugo.git
synced 2025-08-28 22:19:59 +02:00
@@ -45,7 +45,29 @@ type HTTPError struct {
|
||||
Body string
|
||||
}
|
||||
|
||||
func toHTTPError(err error, res *http.Response) *HTTPError {
|
||||
func responseToData(res *http.Response, readBody bool) map[string]any {
|
||||
var body []byte
|
||||
if readBody {
|
||||
body, _ = ioutil.ReadAll(res.Body)
|
||||
}
|
||||
|
||||
m := map[string]any{
|
||||
"StatusCode": res.StatusCode,
|
||||
"Status": res.Status,
|
||||
"TransferEncoding": res.TransferEncoding,
|
||||
"ContentLength": res.ContentLength,
|
||||
"ContentType": res.Header.Get("Content-Type"),
|
||||
}
|
||||
|
||||
if readBody {
|
||||
m["Body"] = string(body)
|
||||
}
|
||||
|
||||
return m
|
||||
|
||||
}
|
||||
|
||||
func toHTTPError(err error, res *http.Response, readBody bool) *HTTPError {
|
||||
if err == nil {
|
||||
panic("err is nil")
|
||||
}
|
||||
@@ -56,19 +78,9 @@ func toHTTPError(err error, res *http.Response) *HTTPError {
|
||||
}
|
||||
}
|
||||
|
||||
var body []byte
|
||||
body, _ = ioutil.ReadAll(res.Body)
|
||||
|
||||
return &HTTPError{
|
||||
error: err,
|
||||
Data: map[string]any{
|
||||
"StatusCode": res.StatusCode,
|
||||
"Status": res.Status,
|
||||
"Body": string(body),
|
||||
"TransferEncoding": res.TransferEncoding,
|
||||
"ContentLength": res.ContentLength,
|
||||
"ContentType": res.Header.Get("Content-Type"),
|
||||
},
|
||||
Data: responseToData(res, readBody),
|
||||
}
|
||||
}
|
||||
|
||||
@@ -80,6 +92,12 @@ func (c *Client) FromRemote(uri string, optionsm map[string]any) (resource.Resou
|
||||
return nil, fmt.Errorf("failed to parse URL for resource %s: %w", uri, err)
|
||||
}
|
||||
|
||||
method := "GET"
|
||||
if s, ok := maps.LookupEqualFold(optionsm, "method"); ok {
|
||||
method = strings.ToUpper(s.(string))
|
||||
}
|
||||
isHeadMethod := method == "HEAD"
|
||||
|
||||
resourceID := calculateResourceID(uri, optionsm)
|
||||
|
||||
_, httpResponse, err := c.cacheGetResource.GetOrCreate(resourceID, func() (io.ReadCloser, error) {
|
||||
@@ -100,15 +118,16 @@ func (c *Client) FromRemote(uri string, optionsm map[string]any) (resource.Resou
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer res.Body.Close()
|
||||
|
||||
httpResponse, err := httputil.DumpResponse(res, true)
|
||||
if err != nil {
|
||||
return nil, toHTTPError(err, res)
|
||||
return nil, toHTTPError(err, res, !isHeadMethod)
|
||||
}
|
||||
|
||||
if res.StatusCode != http.StatusNotFound {
|
||||
if res.StatusCode < 200 || res.StatusCode > 299 {
|
||||
return nil, toHTTPError(fmt.Errorf("failed to fetch remote resource: %s", http.StatusText(res.StatusCode)), res)
|
||||
return nil, toHTTPError(fmt.Errorf("failed to fetch remote resource: %s", http.StatusText(res.StatusCode)), res, !isHeadMethod)
|
||||
|
||||
}
|
||||
}
|
||||
@@ -124,15 +143,24 @@ func (c *Client) FromRemote(uri string, optionsm map[string]any) (resource.Resou
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer res.Body.Close()
|
||||
|
||||
if res.StatusCode == http.StatusNotFound {
|
||||
// Not found. This matches how looksup for local resources work.
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
body, err := ioutil.ReadAll(res.Body)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to read remote resource %q: %w", uri, err)
|
||||
var (
|
||||
body []byte
|
||||
mediaType media.Type
|
||||
)
|
||||
// A response to a HEAD method should not have a body. If it has one anyway, that body must be ignored.
|
||||
// See https://developer.mozilla.org/en-US/docs/Web/HTTP/Methods/HEAD
|
||||
if !isHeadMethod && res.Body != nil {
|
||||
body, err = ioutil.ReadAll(res.Body)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to read remote resource %q: %w", uri, err)
|
||||
}
|
||||
}
|
||||
|
||||
filename := path.Base(rURL.Path)
|
||||
@@ -142,30 +170,38 @@ func (c *Client) FromRemote(uri string, optionsm map[string]any) (resource.Resou
|
||||
}
|
||||
}
|
||||
|
||||
var extensionHints []string
|
||||
|
||||
contentType := res.Header.Get("Content-Type")
|
||||
|
||||
// mime.ExtensionsByType gives a long list of extensions for text/plain,
|
||||
// just use ".txt".
|
||||
if strings.HasPrefix(contentType, "text/plain") {
|
||||
extensionHints = []string{".txt"}
|
||||
if isHeadMethod {
|
||||
// We have no body to work with, so we need to use the Content-Type header.
|
||||
mediaType, _ = media.FromString(contentType)
|
||||
} else {
|
||||
exts, _ := mime.ExtensionsByType(contentType)
|
||||
if exts != nil {
|
||||
extensionHints = exts
|
||||
|
||||
var extensionHints []string
|
||||
|
||||
// mime.ExtensionsByType gives a long list of extensions for text/plain,
|
||||
// just use ".txt".
|
||||
if strings.HasPrefix(contentType, "text/plain") {
|
||||
extensionHints = []string{".txt"}
|
||||
} else {
|
||||
exts, _ := mime.ExtensionsByType(contentType)
|
||||
if exts != nil {
|
||||
extensionHints = exts
|
||||
}
|
||||
}
|
||||
|
||||
// Look for a file extension. If it's .txt, look for a more specific.
|
||||
if extensionHints == nil || extensionHints[0] == ".txt" {
|
||||
if ext := path.Ext(filename); ext != "" {
|
||||
extensionHints = []string{ext}
|
||||
}
|
||||
}
|
||||
|
||||
// Now resolve the media type primarily using the content.
|
||||
mediaType = media.FromContent(c.rs.MediaTypes, extensionHints, body)
|
||||
|
||||
}
|
||||
|
||||
// Look for a file extension. If it's .txt, look for a more specific.
|
||||
if extensionHints == nil || extensionHints[0] == ".txt" {
|
||||
if ext := path.Ext(filename); ext != "" {
|
||||
extensionHints = []string{ext}
|
||||
}
|
||||
}
|
||||
|
||||
// Now resolve the media type primarily using the content.
|
||||
mediaType := media.FromContent(c.rs.MediaTypes, extensionHints, body)
|
||||
if mediaType.IsZero() {
|
||||
return nil, fmt.Errorf("failed to resolve media type for remote resource %q", uri)
|
||||
}
|
||||
|
Reference in New Issue
Block a user