@@ -15,11 +15,34 @@ namespace JsonLD.Core
1515{
1616 public class DocumentLoader
1717 {
18- const int MAX_REDIRECTS = 20 ;
18+ enum JsonLDContentType
19+ {
20+ JsonLD ,
21+ PlainJson ,
22+ Other
23+ }
1924
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+ }
2346
2447 /// <exception cref="JsonLDNet.Core.JsonLdError"></exception>
2548 public RemoteDocument LoadDocument ( string url )
@@ -31,68 +54,50 @@ public RemoteDocument LoadDocument(string url)
3154 public async Task < RemoteDocument > LoadDocumentAsync ( string url )
3255 {
3356 RemoteDocument doc = new RemoteDocument ( url , null ) ;
34-
3557 try
3658 {
37- HttpResponseMessage httpResponseMessage ;
59+ using ( HttpResponseMessage response = await JsonLD . Util . LDHttpClient . FetchAsync ( url ) )
60+ {
3861
39- int redirects = 0 ;
40- int code ;
41- string redirectedUrl = url ;
62+ var code = ( int ) response . StatusCode ;
4263
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 )
5065 {
51- redirectedUrl = location . First ( ) ;
66+ throw new JsonLdError ( JsonLdError . Error . LoadingDocumentFailed , $ "HTTP { code } { url } " ) ;
5267 }
5368
54- code = ( int ) httpResponseMessage . StatusCode ;
55- } while ( redirects ++ < MAX_REDIRECTS && code >= 300 && code < 400 ) ;
69+ var finalUrl = response . RequestMessage . RequestUri . ToString ( ) ;
5670
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 ) ;
6172
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+ }
7477
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 ) )
8180 {
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 ;
8394 }
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- }
9195
92- Stream stream = await httpResponseMessage . Content . ReadAsStreamAsync ( ) ;
96+ Stream stream = await response . Content . ReadAsStreamAsync ( ) ;
9397
94- doc . DocumentUrl = redirectedUrl ;
95- doc . Document = JSONUtils . FromInputStream ( stream ) ;
98+ doc . DocumentUrl = finalUrl ;
99+ doc . Document = JSONUtils . FromInputStream ( stream ) ;
100+ }
96101 }
97102 catch ( JsonLdError )
98103 {
@@ -104,6 +109,5 @@ public async Task<RemoteDocument> LoadDocumentAsync(string url)
104109 }
105110 return doc ;
106111 }
107-
108112 }
109113}
0 commit comments