@@ -40,6 +40,15 @@ var contentTypeToCodecs = map[string][]uint64{
4040 "application/vnd.ipld.dag-cbor" : {uint64 (mc .DagCbor )},
4141}
4242
43+ // contentTypeToExtension maps the HTTP Content Type to the respective file
44+ // extension, to apply them when downloading the file.
45+ var contentTypeToExtension = map [string ]string {
46+ "application/json" : ".json" ,
47+ "application/vnd.ipld.dag-json" : ".dag-json" ,
48+ "application/cbor" : ".cbor" ,
49+ "application/vnd.ipld.dag-cbor" : ".dag-cbor" ,
50+ }
51+
4352func (i * gatewayHandler ) serveCodec (ctx context.Context , w http.ResponseWriter , r * http.Request , resolvedPath ipath.Resolved , contentPath ipath.Path , begin time.Time , requestedContentType string ) {
4453 ctx , span := tracing .Span (ctx , "Gateway" , "ServeCodec" , trace .WithAttributes (attribute .String ("path" , resolvedPath .String ()), attribute .String ("requestedContentType" , requestedContentType )))
4554 defer span .End ()
@@ -108,12 +117,30 @@ func (i *gatewayHandler) serveCodec(ctx context.Context, w http.ResponseWriter,
108117}
109118
110119func (i * gatewayHandler ) serverCodecHTML (ctx context.Context , w http.ResponseWriter , r * http.Request , resolvedPath ipath.Resolved , contentPath ipath.Path ) {
111- w .Write ([]byte ("TODO" ))
120+ body := fmt .Sprintf (`<!DOCTYPE html>
121+ <html lang="en">
122+ <head>
123+ <meta charset="utf-8" />
124+ </head>
125+ <body>
126+ <p>The document you are trying to access cannot be previewed in the browser:</p>
127+ <pre>%s</pre>
128+ <p>Please follow the following links to download the document in other formats:</p>
129+ <ul>
130+ <li><a href="?format=dag-json">DAG-JSON</a></li>
131+ <li><a href="?format=dag-cbor">DAG-CBOR</a></li>
132+ <li><a href="?format=raw">Raw</a></li>
133+ </ul>
134+ </body>
135+ </html>
136+ ` , contentPath .String ())
137+
138+ w .Write ([]byte (body ))
112139}
113140
114141func (i * gatewayHandler ) serveCodecRaw (ctx context.Context , w http.ResponseWriter , r * http.Request , resolvedPath ipath.Resolved , contentPath ipath.Path , contentType string ) {
115142 modtime := addCacheControlHeaders (w , r , contentPath , resolvedPath .Cid ())
116- name := addContentDispositionHeader (w , r , contentPath )
143+ name := setCodecContentDisposition (w , r , resolvedPath , contentType )
117144 w .Header ().Set ("Content-Type" , contentType )
118145 w .Header ().Set ("X-Content-Type-Options" , "nosniff" )
119146
@@ -167,6 +194,7 @@ func (i *gatewayHandler) serveCodecConverted(ctx context.Context, w http.Respons
167194
168195 // Set Cache-Control and read optional Last-Modified time
169196 modtime := addCacheControlHeaders (w , r , contentPath , resolvedPath .Cid ())
197+ setCodecContentDisposition (w , r , resolvedPath , contentType )
170198 w .Header ().Set ("Content-Type" , contentType )
171199 w .Header ().Set ("X-Content-Type-Options" , "nosniff" )
172200
@@ -178,3 +206,19 @@ func (i *gatewayHandler) serveCodecConverted(ctx context.Context, w http.Respons
178206
179207 w .Write (buf .Bytes ())
180208}
209+
210+ func setCodecContentDisposition (w http.ResponseWriter , r * http.Request , resolvedPath ipath.Resolved , contentType string ) string {
211+ var name string
212+ if urlFilename := r .URL .Query ().Get ("filename" ); urlFilename != "" {
213+ name = urlFilename
214+ } else {
215+ ext , ok := contentTypeToExtension [contentType ]
216+ if ! ok {
217+ // Should never happen.
218+ ext = ".bin"
219+ }
220+ name = resolvedPath .Cid ().String () + ext
221+ }
222+ setContentDispositionHeader (w , name , "attachment" )
223+ return name
224+ }
0 commit comments