Open bjuan210302 opened 9 months ago
I think I found the problem.
When you call UploadOrUpdateFile
with options, the options permanently affect the headers of all request:
// storage.go
func (c *Client) UploadOrUpdateFile(
bucketId string,
relativePath string,
data io.Reader,
update bool,
options ...FileOptions,
) (FileUploadResponse, error) {
path := removeEmptyFolderName(bucketId + "/" + relativePath)
uploadURL := c.clientTransport.baseUrl.String() + "/object/" + path
// Check on file options
if len(options) > 0 {
if options[0].CacheControl != nil {
c.clientTransport.header.Set("cache-control", *options[0].CacheControl)
}
if options[0].ContentType != nil {
c.clientTransport.header.Set("content-type", *options[0].ContentType) // <-- content-type is set to whatever you put
}
if options[0].Upsert != nil {
c.clientTransport.header.Set("x-upsert", strconv.FormatBool(*options[0].Upsert))
}
}
This header doesn't get reset back to "application/json", so when you fire the next request (in my case to generate a signed URL to the object) it gets sent with the header you just set. You can see this dumping the request, responses:
// Here I'm uploading a file with the default content type
REQUEST:
%s POST /storage/v1/object/otc-data/orders/20583240451453857792/chat.txt HTTP/1.1
Host: rqvnhdsauyuopdhfgoou.supabase.co
Accept: application/json
Authorization: Bearer xxxxxxx
Content-Type: application/json // <-- unchanged
X-Client-Info: storage-go/v0.7.0
X-Upsert: true
2024/01/24 18:15:34 RESPONSE:
%s HTTP/2.0 200 OK
Access-Control-Allow-Origin: *
Alt-Svc: h3=":443"; ma=86400
Cf-Cache-Status: DYNAMIC
Cf-Ray: 84abfaac5a1a226f-MIA
Content-Type: application/json; charset=utf-8
Date: Wed, 24 Jan 2024 23:15:34 GMT
Sb-Gateway-Mode: direct
Sb-Gateway-Version: 1
Server: cloudflare
Strict-Transport-Security: max-age=2592000; includeSubDomains
Vary: Accept-Encoding
{"Id":"ad7b3555-8b16-4428-aa1c-9cbb9a3f82df","Key":"otc-data/orders/20583240451453857792/chat.txt"}
// And then generating a signed URL
2024/01/24 18:15:34 REQUEST:
%s POST /storage/v1/object/sign/otc-data/orders/20583240451453857792/chat.txt HTTP/1.1
Host: rqvnhdsauyuopdhfgoou.supabase.co
Accept: application/json
Authorization: Bearer xxxx
Content-Type: application/json // <-- unchanged
X-Client-Info: storage-go/v0.7.0
X-Upsert: true
2024/01/24 18:15:34 RESPONSE:
%s HTTP/2.0 200 OK
Access-Control-Allow-Origin: *
Alt-Svc: h3=":443"; ma=86400
Cf-Cache-Status: DYNAMIC
Cf-Ray: 84abfaaedddd226f-MIA
Content-Type: application/json; charset=utf-8
Date: Wed, 24 Jan 2024 23:15:34 GMT
Sb-Gateway-Mode: direct
Sb-Gateway-Version: 1
Server: cloudflare
Strict-Transport-Security: max-age=2592000; includeSubDomains
Vary: Accept-Encoding
{"signedURL":"/object/sign/otc-data/orders/20583240451453857792/chat.txt?token=xxxxxx"}
This happens when you set the content-type
2024/01/24 18:15:35 REQUEST:
%s POST /storage/v1/object/otc-data/orders/20583240451453857792/0.jpg HTTP/1.1
Host: rqvnhdsauyuopdhfgoou.supabase.co
Accept: application/json
Authorization: Bearer xxxx
Content-Type: text/plain // <-- THIS CHANGED TO MATCH FILE
X-Client-Info: storage-go/v0.7.0
X-Upsert: true
// First response is OK
2024/01/24 18:15:35 RESPONSE:
%s HTTP/2.0 200 OK
Access-Control-Allow-Origin: *
Alt-Svc: h3=":443"; ma=86400
Cf-Cache-Status: DYNAMIC
Cf-Ray: 84abfab22a44226f-MIA
Content-Type: application/json; charset=utf-8
Date: Wed, 24 Jan 2024 23:15:36 GMT
Sb-Gateway-Mode: direct
Sb-Gateway-Version: 1
Server: cloudflare
Strict-Transport-Security: max-age=2592000; includeSubDomains
Vary: Accept-Encoding
{"Id":"6d488ac9-0472-4449-9e5a-f843199de539","Key":"otc-data/orders/20583240451453857792/0.jpg"}
2024/01/24 18:15:35 {otc-data/orders/20583240451453857792/0.jpg [] }
2024/01/24 18:15:35
// But when you try to generate the signed URL
2024/01/24 18:15:35 REQUEST:
%s POST /storage/v1/object/sign/otc-data/orders/20583240451453857792/0.jpg HTTP/1.1
Host: rqvnhdsauyuopdhfgoou.supabase.co
Accept: application/json
Authorization: Bearer xxxx
Content-Type: text/plain // <-- and DID NOT reset
X-Client-Info: storage-go/v0.7.0
X-Upsert: true
// So Supabase says something is wrong with your request body
RESPONSE:
%s HTTP/2.0 400 Bad Request
Content-Length: 68
Access-Control-Allow-Origin: *
Alt-Svc: h3=":443"; ma=86400
Cf-Cache-Status: DYNAMIC
Cf-Ray: 84abfab6f975226f-MIA
Content-Type: application/json; charset=utf-8
Date: Wed, 24 Jan 2024 23:15:36 GMT
Sb-Gateway-Mode: direct
Sb-Gateway-Version: 1
Server: cloudflare
Strict-Transport-Security: max-age=2592000; includeSubDomains
Vary: Accept-Encoding
{"statusCode":"400","error":"Error","message":"body must be object"}
If you add c.clientTransport.header.Set("content-type", "application/json")
right after you fire UploadFile request, the subsequent request work as expected.
Bug report
Describe the bug
CreateSignedUrl fails with
body must be object
when target object content-type is different from "application/json"To Reproduce
If you do not set
ContentType
, or set it to the default "application/json" it works.Expected behavior
Method should return the signed url regardless of content type
System information
Additional context
After some digging, the error seems to be coming from the execution of the request at
storage.go@CreateSignedUrl
However, I'm really new to Golang and don't really know what could be causing this. Maybe there's an option to parse non-JSON bodies differently? Also, this is not on Supabase's side, as the NodeJS client seems to do this just fine