Skip to content

Commit 22e7329

Browse files
committed
fix: Fixed #152
1 parent d6bf631 commit 22e7329

2 files changed

Lines changed: 157 additions & 0 deletions

File tree

Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,59 @@
1+
using System.Net.Http;
2+
using System.Net.Http.Headers;
3+
4+
namespace Replicate;
5+
6+
public partial class ReplicateApi
7+
{
8+
#pragma warning disable CA1822 // Partial methods cannot be static
9+
#pragma warning disable CA2000 // Content parts are owned by MultipartFormDataContent
10+
partial void PrepareFilesCreateRequest(
11+
HttpClient httpClient,
12+
HttpRequestMessage httpRequestMessage,
13+
FilesCreateRequest request)
14+
{
15+
// Rebuild the multipart content to work around .NET 6+ Content-Disposition
16+
// formatting changes. Modern .NET no longer quotes name/filename values
17+
// (e.g. name=content instead of name="content"), but Replicate's API
18+
// requires quoted values and returns HTTP 500 without them.
19+
// Also removes the filename* (RFC 5987) extended parameter which
20+
// Replicate does not support.
21+
22+
var fileName = request.Contentname ?? request.Filename ?? "upload";
23+
var contentType = request.Type ?? "application/octet-stream";
24+
25+
var boundary = Guid.NewGuid().ToString("N");
26+
var multipart = new MultipartFormDataContent(boundary);
27+
28+
// Ensure boundary is not quoted in the Content-Type header
29+
multipart.Headers.Remove("Content-Type");
30+
multipart.Headers.TryAddWithoutValidation("Content-Type",
31+
$"multipart/form-data; boundary={boundary}");
32+
33+
var fileContent = new ByteArrayContent(request.Content ?? []);
34+
fileContent.Headers.ContentType = new MediaTypeHeaderValue(contentType);
35+
fileContent.Headers.ContentDisposition = new ContentDispositionHeaderValue("form-data")
36+
{
37+
Name = $"\"{EscapeQuotes("content")}\"",
38+
FileName = $"\"{EscapeQuotes(fileName)}\"",
39+
};
40+
multipart.Add(fileContent);
41+
42+
if (request.Metadata != null)
43+
{
44+
var metadataContent = new StringContent($"{request.Metadata}");
45+
metadataContent.Headers.ContentDisposition = new ContentDispositionHeaderValue("form-data")
46+
{
47+
Name = "\"metadata\"",
48+
};
49+
metadataContent.Headers.ContentType = new MediaTypeHeaderValue("application/json");
50+
multipart.Add(metadataContent);
51+
}
52+
53+
httpRequestMessage.Content = multipart;
54+
}
55+
56+
#pragma warning disable CA1307 // Ordinal is implied for char/string Replace
57+
private static string EscapeQuotes(string value) =>
58+
value.Replace("\\", "\\\\").Replace("\"", "\\\"");
59+
}
Lines changed: 98 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,98 @@
1+
namespace Replicate.IntegrationTests;
2+
3+
public partial class Tests
4+
{
5+
[TestMethod]
6+
public async Task FilesCreateAndDelete()
7+
{
8+
using var api = GetAuthorizedApi();
9+
10+
var content = System.Text.Encoding.UTF8.GetBytes("Hello, Replicate!");
11+
var fileName = "test-file.txt";
12+
13+
var created = await api.FilesCreateAsync(
14+
content: content,
15+
contentname: fileName,
16+
filename: fileName);
17+
18+
try
19+
{
20+
created.Should().NotBeNull();
21+
created.Id.Should().NotBeNullOrEmpty();
22+
created.ContentType.Should().NotBeNullOrEmpty();
23+
created.Size.Should().Be(content.Length);
24+
created.Checksums.Should().NotBeNull();
25+
created.Urls.Should().NotBeNull();
26+
27+
var fetched = await api.FilesGetAsync(created.Id);
28+
fetched.Should().NotBeNull();
29+
fetched.Id.Should().Be(created.Id);
30+
}
31+
finally
32+
{
33+
await api.FilesDeleteAsync(created.Id);
34+
}
35+
}
36+
37+
[TestMethod]
38+
public async Task FilesList()
39+
{
40+
using var api = GetAuthorizedApi();
41+
42+
var response = await api.FilesListAsync();
43+
44+
response.Should().NotBeNull();
45+
response.Results.Should().NotBeNull();
46+
}
47+
48+
[TestMethod]
49+
public async Task FilesCreateWithMetadata()
50+
{
51+
using var api = GetAuthorizedApi();
52+
53+
var content = System.Text.Encoding.UTF8.GetBytes("metadata test");
54+
var fileName = "test-metadata.txt";
55+
var metadata = "{\"test_key\": \"test_value\"}";
56+
57+
var created = await api.FilesCreateAsync(
58+
content: content,
59+
contentname: fileName,
60+
filename: fileName,
61+
metadata: metadata);
62+
63+
try
64+
{
65+
created.Should().NotBeNull();
66+
created.Id.Should().NotBeNullOrEmpty();
67+
}
68+
finally
69+
{
70+
await api.FilesDeleteAsync(created.Id);
71+
}
72+
}
73+
74+
[TestMethod]
75+
public async Task FilesCreateWithContentType()
76+
{
77+
using var api = GetAuthorizedApi();
78+
79+
var content = System.Text.Encoding.UTF8.GetBytes("{\"key\": \"value\"}");
80+
var fileName = "test-file.json";
81+
82+
var created = await api.FilesCreateAsync(
83+
content: content,
84+
contentname: fileName,
85+
filename: fileName,
86+
type: "application/json");
87+
88+
try
89+
{
90+
created.Should().NotBeNull();
91+
created.ContentType.Should().Be("application/json");
92+
}
93+
finally
94+
{
95+
await api.FilesDeleteAsync(created.Id);
96+
}
97+
}
98+
}

0 commit comments

Comments
 (0)