@@ -2,21 +2,44 @@ import 'dart:async';
22import 'dart:convert' ;
33import 'dart:typed_data' ;
44
5+ import 'package:flutter/foundation.dart' show kIsWeb;
56import 'package:flutter/material.dart' hide Element;
67import 'package:flutter_chat_core/flutter_chat_core.dart'
78 show LinkPreviewData, ImagePreviewData;
89import 'package:html/dom.dart' show Document, Element;
910import 'package:html/parser.dart' as parser show parse;
1011import 'package:http/http.dart' as http show Request, Client, Response;
12+ import 'package:punycode/punycode.dart' as puny;
1113
1214import 'types.dart' ;
1315
1416String _calculateUrl (String baseUrl, String ? proxy) {
17+ var urlToReturn = baseUrl;
18+
19+ final domainRegex = RegExp (r'^(?:(http|https|ftp):\/\/)?([^\/?#]+)' );
20+ final match = domainRegex.firstMatch (baseUrl);
21+
22+ if (match != null ) {
23+ final originalDomain = match.group (2 )! ;
24+
25+ final labels = originalDomain.split ('.' );
26+ if (labels.length <= 10 ) {
27+ final encodedLabels =
28+ labels.map ((label) {
29+ final isAscii = label.runes.every ((r) => r < 128 );
30+ return isAscii ? label : 'xn--${puny .punycodeEncode (label )}' ;
31+ }).toList ();
32+
33+ final punycodedDomain = encodedLabels.join ('.' );
34+ urlToReturn = baseUrl.replaceFirst (originalDomain, punycodedDomain);
35+ }
36+ }
37+
1538 if (proxy != null ) {
16- return '$proxy $baseUrl ' ;
39+ return '$proxy $urlToReturn ' ;
1740 }
1841
19- return baseUrl ;
42+ return urlToReturn ;
2043}
2144
2245String ? _getMetaContent (Document document, String propertyValue) {
@@ -155,7 +178,7 @@ Future<String> _getBiggestImageUrl(
155178
156179Future <http.Response ?> _getRedirectedResponse (
157180 Uri uri, {
158- String ? userAgent ,
181+ Map < String , String > ? headers ,
159182 int maxRedirects = 5 ,
160183 Duration timeout = const Duration (seconds: 5 ),
161184 http.Client ? client,
@@ -164,10 +187,11 @@ Future<http.Response?> _getRedirectedResponse(
164187 var redirectCount = 0 ;
165188
166189 while (redirectCount < maxRedirects) {
167- final request =
168- http.Request ('GET' , uri)
169- ..followRedirects = false
170- ..headers.addAll ({if (userAgent != null ) 'User-Agent' : userAgent});
190+ final request = http.Request ('GET' , uri)..followRedirects = false ;
191+
192+ if (headers != null ) {
193+ request.headers.addAll (headers);
194+ }
171195
172196 final streamedResponse = await httpClient.send (request).timeout (timeout);
173197
@@ -187,6 +211,7 @@ Future<http.Response?> _getRedirectedResponse(
187211/// Parses provided text and returns [PreviewData] for the first found link.
188212Future <LinkPreviewData ?> getLinkPreviewData (
189213 String text, {
214+ Map <String , String >? headers,
190215 String ? proxy,
191216 Duration ? requestTimeout,
192217 String ? userAgent,
@@ -204,7 +229,7 @@ Future<LinkPreviewData?> getLinkPreviewData(
204229 text.replaceAllMapped (emailRegexp, (match) => '' ).trim ();
205230 if (textWithoutEmails.isEmpty) return null ;
206231
207- final urlRegexp = RegExp (regexLink, caseSensitive: false );
232+ final urlRegexp = RegExp (regexLink, caseSensitive: false , unicode : true );
208233 final matches = urlRegexp.allMatches (textWithoutEmails);
209234 if (matches.isEmpty) return null ;
210235
@@ -218,10 +243,26 @@ Future<LinkPreviewData?> getLinkPreviewData(
218243 }
219244 previewDataUrl = _calculateUrl (url, proxy);
220245 final uri = Uri .parse (previewDataUrl);
246+
247+ final defaultHeaders =
248+ kIsWeb
249+ ? {
250+ 'Access-Control-Allow-Origin' : '*' ,
251+ 'Content-Type' : 'application/json' ,
252+ 'Accept' : '*/*' ,
253+ }
254+ : {};
255+
256+ final effectiveHeaders = < String , String > {
257+ ...defaultHeaders,
258+ 'User-Agent' : userAgent ?? 'WhatsApp/2' ,
259+ ...? headers,
260+ };
261+
221262 final response = await _getRedirectedResponse (
222263 uri,
264+ headers: effectiveHeaders,
223265 timeout: requestTimeout ?? const Duration (seconds: 5 ),
224- userAgent: userAgent ?? 'WhatsApp/2' ,
225266 );
226267
227268 if (response == null || response.statusCode != 200 ) {
@@ -307,4 +348,4 @@ const regexImageContentType = r'image\/*';
307348
308349/// Regex to find all links in the text.
309350const regexLink =
310- r'((http|ftp|https):\/\/)?([\w_ -]+(?:(?:\.[\w_ -]*[a-zA-Z_ ][\w_ -]*)+))([\w .,@?^=%&:/~+#-]*[\w @?^=%&/~+#-])?[^\.\s]' ;
351+ r'((http|ftp|https):\/\/)?(([\p{L}\p{N}_ -]+) (?:(?:\.([\p{L}\p{N}_ -]*[\p{L}_ ][\p{L}\p{N}_ -]*)) +))([\p{L}\p{N} .,@?^=%&:/~+#-]*[\p{L}\p{N} @?^=%&/~+#-])?[^\.\s]' ;
0 commit comments