2.17Sending from a cURL Command
When integrating with or debugging third-party APIs, cURL commands are the most common way to describe requests. The framework has a built-in cURL command parsing engine that supports initiating HTTP requests directly from a native cURL command string in one step, covering common options (such as -X, -H, -d, -F, -u, --data-urlencode, --max-time, --http2, etc.), and can be freely extended with custom flags.
Usage is very simple: pass the cURL command directly into HttpRequestBuilder.FromCurl(), then send it via IHttpRemoteService.
var result = await httpRemoteService.SendAsStringAsync( HttpRequestBuilder.FromCurl("curl https://furion.net"));The following examples demonstrate specific usage across several scenarios.
A Regular GET Request
var result = await httpRemoteService.SendAsStringAsync( HttpRequestBuilder.FromCurl("curl https://furion.net"));With Query Parameters and a JSON Request Body
var result = await httpRemoteService.SendAsStringAsync( HttpRequestBuilder.FromCurl(""" curl -k -X POST 'https://localhost:7044/HttpRemote/AddModel?query1=10&query2=hello' \ -H 'Content-Type: application/json' \ -d '{ "id": 1, "name": "sample" }' """));Multipart Form (File Upload + Regular Fields)
var result = await httpRemoteService.SendAsStringAsync( HttpRequestBuilder.FromCurl(""" curl -k -X POST 'https://localhost:7044/HttpRemote/AddForm?id=100' \ -F 'Id=100' \ -F 'Name=furion' \ -F 'File=@C:\Workspaces\httptest.jpg' """));File uploads use the @ prefix. Paths support local absolute paths (such as C:\...) or network URLs (such as @https://example.com/avatar.png).
URL-Encoded Form (application/x-www-form-urlencoded)
Use -d to send URL-encoded data:
var result = await httpRemoteService.SendAsStringAsync( HttpRequestBuilder.FromCurl(""" curl -k -X POST 'https://localhost:7044/HttpRemote/AddUrlForm' \ -H 'Content-Type: application/x-www-form-urlencoded' \ -d 'id=200&name=furion' """));Use --data-urlencode to automatically encode special characters such as spaces:
var result = await httpRemoteService.SendAsStringAsync( HttpRequestBuilder.FromCurl(""" curl -k -X POST 'https://localhost:7044/HttpRemote/AddUrlForm' \ --data-urlencode 'id=200' \ --data-urlencode 'name=fu rion' """));Uploading a Single File
var result = await httpRemoteService.SendAsStringAsync( HttpRequestBuilder.FromCurl(""" curl -k -X POST 'https://localhost:7044/HttpRemote/AddFile' \ -F 'file=@C:\Workspaces\httptest.jpg' """));Uploading Multiple Files
var result = await httpRemoteService.SendAsStringAsync( HttpRequestBuilder.FromCurl(""" curl -k -X POST 'https://localhost:7044/HttpRemote/AddFiles' \ -F 'files=@C:\Workspaces\httptest.jpg' \ -F 'files=@C:\Workspaces\httptest.jpg' """));Sending a Raw String (such as "This is a raw string")
var result = await httpRemoteService.SendAsStringAsync( HttpRequestBuilder.FromCurl(""" curl -k -X POST 'https://localhost:7044/HttpRemote/RawString' \ -H 'Content-Type: application/json' \ -d '"This is a raw string"' """));A Request with Authentication Information
var result = await httpRemoteService.SendAsStringAsync( HttpRequestBuilder.FromCurl(""" curl -X POST https://jsonplaceholder.typicode.com/posts \ -H "Content-Type: application/json" \ -u testuser:testpass \ -d '{"title":"Test"}' """));Ignoring Output Options (such as -o)
Some cURL options (such as -o, -v, -s) are output controls. They do not affect request building and are automatically ignored. For example:
var result = await httpRemoteService.SendAsStringAsync( HttpRequestBuilder.FromCurl("curl -o qr.png \"https://api.qrserver.com/v1/create-qr-code/?size=150x150&data=Hello\""));This command sends the GET request and obtains the response content normally, but it does not save the result to a file (file saving must be handled by you).
Extending Custom cURL Options
The framework's cURL parser uses a pluggable extractor architecture, where each cURL option is handled by an independent IHttpCurlExtractor implementation. You can support private cURL flags (such as --my-flag) by adding custom extractors without modifying the framework source code.
Implementing a Custom Extractor
The most convenient way to create a custom extractor is to inherit from the HttpCurlExtractorBase base class, which already encapsulates cursor advancement and argument consumption logic:
/// <summary>/// Custom --my-flag extractor/// </summary>internal sealed class CurlMyFlagExtractor : HttpCurlExtractorBase{ /// <summary> /// The set of flags to match (case-insensitive) /// </summary> protected override string[] Flags => ["--my-flag"]; /// <summary> /// Whether an argument is required. Defaults to true; set to false if the flag takes no argument. /// </summary> protected override bool RequiresArgument => true; /// <summary> /// The specific operation to perform when the flag is matched /// </summary> /// <param name="httpRequestBuilder">Request builder</param> /// <param name="flag">The currently matched flag (already lowercased)</param> /// <param name="argument">The argument value carried, or null if there is no argument</param> protected override void Extract(HttpRequestBuilder httpRequestBuilder, string flag, string? argument) { // Configure the builder based on the flag here if (!string.IsNullOrWhiteSpace(argument)) { // Example: put the argument value into the X-My-Flag request header httpRequestBuilder.WithHeader("X-My-Flag", argument); } }}For more complex scenarios (such as needing to control priority or manage the cursor manually), you can implement the IHttpCurlExtractor interface directly; if ordering is needed, additionally implement the IOrderedHttpCurlExtractor interface (the smaller the Order, the higher the priority).
Registering a Custom Extractor
Custom extractors are injected through a configuration delegate when calling FromCurl:
var builder = HttpRequestBuilder.FromCurl( "curl --my-flag hello-world http://example.com", options => options.AddExtractor(new CurlMyFlagExtractor()));To remove a built-in extractor, use options.RemoveExtractor<T>(). For example:
var builder = HttpRequestBuilder.FromCurl( "curl http://example.com", options => options.RemoveExtractor<CurlHeaderExtractor>());Context Object Reference
HttpCurlParsingContext provides rich cursor-control methods:
| Member | Description |
|---|---|
CurrentToken | Gets the Token currently pointed to |
PeekNext() | Peeks at the next Token (without moving the pointer) |
Advance(count) | Advances forward by the specified number of steps (default 1) |
CurrentTokenMatches(flags) | Checks whether the current Token matches the given set of flags (case-insensitive) |
IsEndOfTokens | Whether the end of the Token list has been reached |
When implementing IHttpCurlExtractor directly, you must call Advance yourself to consume Tokens; otherwise it leads to an infinite parsing loop.
Reference Implementations
All built-in extractors (such as CurlMethodExtractor, CurlFormExtractor, etc.) are built on the same interfaces and base classes. You can view their source code in the repository as a reference: View built-in extractor source code