@@ -15,11 +15,34 @@ namespace JsonLD.Core
15
15
{
16
16
public class DocumentLoader
17
17
{
18
- const int MAX_REDIRECTS = 20 ;
18
+ enum JsonLDContentType
19
+ {
20
+ JsonLD ,
21
+ PlainJson ,
22
+ Other
23
+ }
19
24
20
- /// <summary>An HTTP Accept header that prefers JSONLD.</summary>
21
- /// <remarks>An HTTP Accept header that prefers JSONLD.</remarks>
22
- public const string AcceptHeader = "application/ld+json, application/json;q=0.9, application/javascript;q=0.5, text/javascript;q=0.5, text/plain;q=0.2, */*;q=0.1" ;
25
+ JsonLDContentType GetJsonLDContentType ( string contentTypeStr )
26
+ {
27
+ JsonLDContentType contentType ;
28
+
29
+ switch ( contentTypeStr )
30
+ {
31
+ case "application/ld+json" :
32
+ contentType = JsonLDContentType . JsonLD ;
33
+ break ;
34
+ // From RFC 6839, it looks like plain JSON is content type application/json and any MediaType ending in "+json".
35
+ case "application/json" :
36
+ case string type when type . EndsWith ( "+json" ) :
37
+ contentType = JsonLDContentType . PlainJson ;
38
+ break ;
39
+ default :
40
+ contentType = JsonLDContentType . Other ;
41
+ break ;
42
+ }
43
+
44
+ return contentType ;
45
+ }
23
46
24
47
/// <exception cref="JsonLDNet.Core.JsonLdError"></exception>
25
48
public RemoteDocument LoadDocument ( string url )
@@ -31,68 +54,50 @@ public RemoteDocument LoadDocument(string url)
31
54
public async Task < RemoteDocument > LoadDocumentAsync ( string url )
32
55
{
33
56
RemoteDocument doc = new RemoteDocument ( url , null ) ;
34
-
35
57
try
36
58
{
37
- HttpResponseMessage httpResponseMessage ;
59
+ using ( HttpResponseMessage response = await JsonLD . Util . LDHttpClient . FetchAsync ( url ) )
60
+ {
38
61
39
- int redirects = 0 ;
40
- int code ;
41
- string redirectedUrl = url ;
62
+ var code = ( int ) response . StatusCode ;
42
63
43
- // Manually follow redirects because .NET Core refuses to auto-follow HTTPS->HTTP redirects.
44
- do
45
- {
46
- HttpRequestMessage httpRequestMessage = new HttpRequestMessage ( HttpMethod . Get , redirectedUrl ) ;
47
- httpRequestMessage . Headers . Add ( "Accept" , AcceptHeader ) ;
48
- httpResponseMessage = await JSONUtils . _HttpClient . SendAsync ( httpRequestMessage ) ;
49
- if ( httpResponseMessage . Headers . TryGetValues ( "Location" , out var location ) )
64
+ if ( code >= 400 )
50
65
{
51
- redirectedUrl = location . First ( ) ;
66
+ throw new JsonLdError ( JsonLdError . Error . LoadingDocumentFailed , $ "HTTP { code } { url } " ) ;
52
67
}
53
68
54
- code = ( int ) httpResponseMessage . StatusCode ;
55
- } while ( redirects ++ < MAX_REDIRECTS && code >= 300 && code < 400 ) ;
69
+ var finalUrl = response . RequestMessage . RequestUri . ToString ( ) ;
56
70
57
- if ( redirects >= MAX_REDIRECTS )
58
- {
59
- throw new JsonLdError ( JsonLdError . Error . LoadingDocumentFailed , $ "Too many redirects - { url } ") ;
60
- }
71
+ var contentType = GetJsonLDContentType ( response . Content . Headers . ContentType . MediaType ) ;
61
72
62
- if ( code >= 400 )
63
- {
64
- throw new JsonLdError ( JsonLdError . Error . LoadingDocumentFailed , $ "HTTP { code } { url } ") ;
65
- }
66
-
67
- bool isJsonld = httpResponseMessage . Content . Headers . ContentType . MediaType == "application/ld+json" ;
68
-
69
- // From RFC 6839, it looks like we should accept application/json and any MediaType ending in "+json".
70
- if ( httpResponseMessage . Content . Headers . ContentType . MediaType != "application/json" && ! httpResponseMessage . Content . Headers . ContentType . MediaType . EndsWith ( "+json" ) )
71
- {
72
- throw new JsonLdError ( JsonLdError . Error . LoadingDocumentFailed , url ) ;
73
- }
73
+ if ( contentType == JsonLDContentType . Other )
74
+ {
75
+ throw new JsonLdError ( JsonLdError . Error . LoadingDocumentFailed , url ) ;
76
+ }
74
77
75
- if ( ! isJsonld && httpResponseMessage . Headers . TryGetValues ( "Link" , out var linkHeaders ) )
76
- {
77
- linkHeaders = linkHeaders . SelectMany ( ( h ) => h . Split ( "," . ToCharArray ( ) ) )
78
- . Select ( h => h . Trim ( ) ) . ToArray ( ) ;
79
- IEnumerable < string > linkedContexts = linkHeaders . Where ( v => v . EndsWith ( "rel=\" http://www.w3.org/ns/json-ld#context\" " ) ) ;
80
- if ( linkedContexts . Count ( ) > 1 )
78
+ // For plain JSON, see if there's a context document linked in the HTTP response headers.
79
+ if ( contentType == JsonLDContentType . PlainJson && response . Headers . TryGetValues ( "Link" , out var linkHeaders ) )
81
80
{
82
- throw new JsonLdError ( JsonLdError . Error . MultipleContextLinkHeaders ) ;
81
+ linkHeaders = linkHeaders . SelectMany ( ( h ) => h . Split ( "," . ToCharArray ( ) ) )
82
+ . Select ( h => h . Trim ( ) ) . ToArray ( ) ;
83
+ IEnumerable < string > linkedContexts = linkHeaders . Where ( v => v . EndsWith ( "rel=\" http://www.w3.org/ns/json-ld#context\" " ) ) ;
84
+ if ( linkedContexts . Count ( ) > 1 )
85
+ {
86
+ throw new JsonLdError ( JsonLdError . Error . MultipleContextLinkHeaders ) ;
87
+ }
88
+ string header = linkedContexts . First ( ) ;
89
+ string linkedUrl = header . Substring ( 1 , header . IndexOf ( ">" ) - 1 ) ;
90
+ string resolvedUrl = URL . Resolve ( finalUrl , linkedUrl ) ;
91
+ var remoteContext = this . LoadDocument ( resolvedUrl ) ;
92
+ doc . contextUrl = remoteContext . documentUrl ;
93
+ doc . context = remoteContext . document ;
83
94
}
84
- string header = linkedContexts . First ( ) ;
85
- string linkedUrl = header . Substring ( 1 , header . IndexOf ( ">" ) - 1 ) ;
86
- string resolvedUrl = URL . Resolve ( redirectedUrl , linkedUrl ) ;
87
- var remoteContext = this . LoadDocument ( resolvedUrl ) ;
88
- doc . contextUrl = remoteContext . documentUrl ;
89
- doc . context = remoteContext . document ;
90
- }
91
95
92
- Stream stream = await httpResponseMessage . Content . ReadAsStreamAsync ( ) ;
96
+ Stream stream = await response . Content . ReadAsStreamAsync ( ) ;
93
97
94
- doc . DocumentUrl = redirectedUrl ;
95
- doc . Document = JSONUtils . FromInputStream ( stream ) ;
98
+ doc . DocumentUrl = finalUrl ;
99
+ doc . Document = JSONUtils . FromInputStream ( stream ) ;
100
+ }
96
101
}
97
102
catch ( JsonLdError )
98
103
{
@@ -104,6 +109,5 @@ public async Task<RemoteDocument> LoadDocumentAsync(string url)
104
109
}
105
110
return doc ;
106
111
}
107
-
108
112
}
109
113
}
0 commit comments