@@ -141,7 +141,7 @@ func inlineRemoteCSS(h string) (string, error) {
141141 attributes := link .Attr
142142 for _ , a := range attributes {
143143 if a .Key == "href" {
144- if ! isURL (a .Val ) {
144+ if ! isValidURL (a .Val ) {
145145 // skip invalid URL
146146 continue
147147 }
@@ -151,9 +151,9 @@ func inlineRemoteCSS(h string) (string, error) {
151151 return h , nil
152152 }
153153
154- resp , err := downloadToBytes (a .Val )
154+ resp , err := downloadCSSToBytes (a .Val )
155155 if err != nil {
156- logger .Log ().Warnf ("[html-check] failed to download %s" , a . Val )
156+ logger .Log ().Warnf ("[html-check] %s" , err . Error () )
157157 continue
158158 }
159159
@@ -182,8 +182,10 @@ func inlineRemoteCSS(h string) (string, error) {
182182 return newDoc , nil
183183}
184184
185- // DownloadToBytes returns a []byte slice from a URL
186- func downloadToBytes (url string ) ([]byte , error ) {
185+ // DownloadCSSToBytes returns a []byte slice from a URL.
186+ // It requires the HTTP response code to be 200 and the content-type to be text/css.
187+ // It will download a maximum of 5MB.
188+ func downloadCSSToBytes (url string ) ([]byte , error ) {
187189 client := http.Client {
188190 Timeout : 5 * time .Second ,
189191 }
@@ -200,18 +202,29 @@ func downloadToBytes(url string) ([]byte, error) {
200202 return nil , err
201203 }
202204
203- body , err := io .ReadAll (resp .Body )
205+ ct := strings .ToLower (resp .Header .Get ("content-type" ))
206+ if ! strings .Contains (ct , "text/css" ) {
207+ err := fmt .Errorf ("invalid CSS content-type from %s: \" %s\" (expected \" text/css\" )" , url , ct )
208+ return nil , err
209+ }
210+
211+ // set a limit on the number of bytes to read - max 5MB
212+ limit := int64 (5242880 )
213+ limitedReader := & io.LimitedReader {R : resp .Body , N : limit }
214+
215+ body , err := io .ReadAll (limitedReader )
204216 if err != nil {
205217 return nil , err
206218 }
207219
208220 return body , nil
209221}
210222
211- // Test if str is a URL
212- func isURL (str string ) bool {
223+ // Test if the string is a supported URL.
224+ // The URL must have the "http" or "https" scheme, and must not contain any login info (http://user:pass@<host>).
225+ func isValidURL (str string ) bool {
213226 u , err := url .Parse (str )
214- return err == nil && (u .Scheme == "http" || u .Scheme == "https" ) && u .Host != ""
227+ return err == nil && (u .Scheme == "http" || u .Scheme == "https" ) && u .Hostname () != "" && u . User == nil
215228}
216229
217230// Test the HTML for inline CSS styles and styling attributes
0 commit comments