4
4
"bytes"
5
5
"context"
6
6
"crypto/sha256"
7
+ "crypto/tls"
7
8
"encoding/base64"
8
9
"encoding/json"
9
10
"fmt"
@@ -94,6 +95,11 @@ func makeUrlPreviewHandler(
94
95
}
95
96
}
96
97
98
+ urlParsed , err := url .Parse (pUrl )
99
+ if err != nil {
100
+ return util .ErrorResponse (ErrorMissingUrl )
101
+ }
102
+
97
103
hash := getHashFromString (pUrl )
98
104
99
105
// Get for url preview from in-memory cache
@@ -136,6 +142,7 @@ func makeUrlPreviewHandler(
136
142
// we defer caching the url preview response as well as signalling the waiting goroutines
137
143
// about the completion of the request
138
144
defer func () {
145
+
139
146
urlPreviewCacheItem := & types.UrlPreviewCacheRecord {
140
147
Created : time .Now ().Unix (),
141
148
}
@@ -164,38 +171,25 @@ func makeUrlPreviewHandler(
164
171
if err != nil {
165
172
activeUrlPreviewRequest .Error = err
166
173
} else {
167
- defer func () {
168
- err := resp .Body .Close ()
169
- if err != nil {
170
- logger .WithError (err ).Error ("unable to close response body" )
171
- }
172
- }()
174
+ defer resp .Body .Close () // nolint: errcheck
173
175
174
176
var result * types.UrlPreview
175
- var err , err2 error
176
- var imgUrl * url.URL
177
+ var err error
177
178
var imgReader * http.Response
178
179
var mediaData * types.MediaMetadata
179
180
var width , height int
180
181
181
182
if strings .HasPrefix (resp .Header .Get ("Content-Type" ), "text/html" ) {
182
183
// The url is a webpage - get data from the meta tags
183
- result = getPreviewFromHTML (resp , pUrl )
184
+ result = getPreviewFromHTML (resp , urlParsed )
184
185
if result .ImageUrl != "" {
185
- // The page has an og:image link
186
- if imgUrl , err2 = url .Parse (result .ImageUrl ); err2 == nil {
187
- imgReader , err2 = downloadUrl (result .ImageUrl , time .Duration (cfg .UrlPreviewTimeout )* time .Second )
188
- if err2 == nil {
189
- // Download image and store it as a thumbnail
190
- mediaData , width , height , err2 = downloadAndStoreImage (imgUrl .Path , req .Context (), imgReader , cfg , device , db , activeThumbnailGeneration , logger )
191
- }
192
- }
193
- // In case of any error in image download
194
- // we don't show the original URL as it is insecure for the room users
195
- if err2 != nil {
196
- result .ImageUrl = ""
186
+ // In case of an image in the preview we download it
187
+ if imgReader , err = downloadUrl (result .ImageUrl , time .Duration (cfg .UrlPreviewTimeout )* time .Second ); err == nil {
188
+ mediaData , width , height , _ = downloadAndStoreImage ("url_preview" , req .Context (), imgReader , cfg , device , db , activeThumbnailGeneration , logger )
197
189
}
198
-
190
+ // We don't show the original image in the preview
191
+ // as it is insecure for room members
192
+ result .ImageUrl = ""
199
193
}
200
194
} else if strings .HasPrefix (resp .Header .Get ("Content-Type" ), "image/" ) {
201
195
// The url is an image link
@@ -275,7 +269,10 @@ func checkActivePreviewResponse(activeUrlPreviewRequests *types.ActiveUrlPreview
275
269
}
276
270
277
271
func downloadUrl (url string , t time.Duration ) (* http.Response , error ) {
278
- client := http.Client {Timeout : t }
272
+ tr := & http.Transport {
273
+ TLSClientConfig : & tls.Config {InsecureSkipVerify : true },
274
+ }
275
+ client := http.Client {Timeout : t , Transport : tr }
279
276
resp , err := client .Get (url )
280
277
if err != nil {
281
278
return nil , err
@@ -287,15 +284,18 @@ func downloadUrl(url string, t time.Duration) (*http.Response, error) {
287
284
return resp , nil
288
285
}
289
286
290
- func getPreviewFromHTML (resp * http.Response , url string ) * types.UrlPreview {
287
+ func getPreviewFromHTML (resp * http.Response , urlParsed * url.URL ) * types.UrlPreview {
288
+
291
289
fields := getMetaFieldsFromHTML (resp )
292
290
preview := & types.UrlPreview {
293
291
Title : fields ["og:title" ],
294
292
Description : fields ["og:description" ],
293
+ Type : fields ["og:type" ],
294
+ Url : fields ["og:url" ],
295
295
}
296
296
297
297
if fields ["og:title" ] == "" {
298
- preview .Title = url
298
+ preview .Title = urlParsed . String ()
299
299
}
300
300
if fields ["og:image" ] != "" {
301
301
preview .ImageUrl = fields ["og:image" ]
@@ -305,14 +305,19 @@ func getPreviewFromHTML(resp *http.Response, url string) *types.UrlPreview {
305
305
preview .ImageUrl = fields ["og:image:secure_url" ]
306
306
}
307
307
308
- if fields ["og:image:width" ] != "" {
309
- if width , err := strconv .Atoi (fields ["og:image:width" ]); err == nil {
310
- preview .ImageWidth = width
311
- }
312
- }
313
- if fields ["og:image:height" ] != "" {
314
- if height , err := strconv .Atoi (fields ["og:image:height" ]); err == nil {
315
- preview .ImageHeight = height
308
+ if preview .ImageUrl != "" {
309
+ if imgUrl , err := url .Parse (preview .ImageUrl ); err == nil {
310
+ // Use the same scheme and host as the original URL if empty
311
+ if imgUrl .Scheme == "" {
312
+ imgUrl .Scheme = urlParsed .Scheme
313
+ }
314
+ // Use the same host as the original URL if empty
315
+ if imgUrl .Host == "" {
316
+ imgUrl .Host = urlParsed .Host
317
+ }
318
+ preview .ImageUrl = imgUrl .String ()
319
+ } else {
320
+ preview .ImageUrl = ""
316
321
}
317
322
}
318
323
@@ -371,11 +376,11 @@ func downloadAndStoreImage(
371
376
if err != nil {
372
377
return nil , width , height , err
373
378
}
374
- img , err := thumbnailer .ReadFile (string (filePath ))
379
+ width , height , err := thumbnailer .GetImageSize (string (filePath ))
375
380
if err != nil {
376
381
return nil , width , height , err
377
382
}
378
- return existingMetadata , img . Bounds (). Dx (), img . Bounds (). Dy () , nil
383
+ return existingMetadata , width , height , nil
379
384
}
380
385
381
386
tmpFileName := filepath .Join (string (tmpDir ), "content" )
@@ -386,22 +391,34 @@ func downloadAndStoreImage(
386
391
}
387
392
logger .WithField ("contentType" , fileType ).Debug ("uploaded file is an image" )
388
393
389
- // Create a thumbnail from the image
390
- thumbnailPath := tmpFileName + ".thumbnail"
394
+ var thumbnailPath string
391
395
392
- width , height , err = createThumbnail (types .Path (tmpFileName ), types .Path (thumbnailPath ), types .ThumbnailSize (cfg .UrlPreviewThumbnailSize ),
393
- hash , activeThumbnailGeneration , cfg .MaxThumbnailGenerators , logger )
394
- if err != nil {
395
- if errors .Is (err , thumbnailer .ErrThumbnailTooLarge ) {
396
- // In case the image is smaller than the thumbnail size
397
- // we don't create a thumbnail
398
- thumbnailPath = tmpFileName
399
- } else {
396
+ if cfg .UrlPreviewThumbnailSize .Width != 0 {
397
+ // Create a thumbnail from the image
398
+ thumbnailPath = tmpFileName + ".thumbnail"
399
+
400
+ width , height , err = createThumbnail (types .Path (tmpFileName ), types .Path (thumbnailPath ), types .ThumbnailSize (cfg .UrlPreviewThumbnailSize ),
401
+ hash , activeThumbnailGeneration , cfg .MaxThumbnailGenerators , logger )
402
+ if err != nil {
403
+ if errors .Is (err , thumbnailer .ErrThumbnailTooLarge ) {
404
+ // In case the image is smaller than the thumbnail size
405
+ // we don't create a thumbnail
406
+ thumbnailPath = tmpFileName
407
+ } else {
408
+ return nil , width , height , err
409
+ }
410
+ }
411
+ } else {
412
+ // No thumbnail size specified, use the original image
413
+ thumbnailPath = tmpFileName
414
+ width , height , err = thumbnailer .GetImageSize (thumbnailPath )
415
+ if err != nil {
400
416
return nil , width , height , err
401
417
}
418
+
402
419
}
403
420
404
- thumbnailFileInfo , err := os .Stat (string ( thumbnailPath ) )
421
+ thumbnailFileInfo , err := os .Stat (thumbnailPath )
405
422
if err != nil {
406
423
logger .WithError (err ).Error ("unable to get thumbnail file info" )
407
424
return nil , width , height , err
@@ -564,12 +581,7 @@ func detectFileType(filePath string, logger *log.Entry) (string, error) {
564
581
logger .WithError (err ).Error ("unable to open image file" )
565
582
return "" , err
566
583
}
567
- defer func () {
568
- err := file .Close ()
569
- if err != nil {
570
- logger .WithError (err ).Error ("unable to close image file" )
571
- }
572
- }()
584
+ defer file .Close () // nolint: errcheck
573
585
574
586
buf := make ([]byte , 512 )
575
587
@@ -605,6 +617,8 @@ func getMetaFieldsFromHTML(resp *http.Response) map[string]string {
605
617
"og:image:width" ,
606
618
"og:image:height" ,
607
619
"og:image:type" ,
620
+ "og:type" ,
621
+ "og:url" ,
608
622
}
609
623
fieldsMap := make (map [string ]bool , len (fieldsToGet ))
610
624
for _ , field := range fieldsToGet {
0 commit comments