Skip to content

Commit a5ff34d

Browse files
authored
Merge pull request #47 from WeihanLi/dev
0.5.0
2 parents 84a50c5 + f18df24 commit a5ff34d

37 files changed

+208
-134
lines changed

.editorconfig

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,12 @@ root = true
88
indent_style = space
99
# (Please don't specify an indent_size here; that has too many unintended consequences.)
1010

11+
# Shell scripts
12+
[*.sh]
13+
end_of_line = lf
14+
[*.{cmd,bat}]
15+
end_of_line = crlf
16+
1117
# Code files
1218
[*.{cs,csx,vb,vbx}]
1319
indent_size = 4

.github/workflows/dotnet-outdated.yml

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,8 +5,9 @@ on:
55
# - cron: '0 1 * * *'
66
push:
77
branches:
8-
- "main"
9-
- "dev"
8+
# - "main"
9+
# - "dev"
10+
- "test"
1011
jobs:
1112
build:
1213
runs-on: ubuntu-latest

Directory.Build.props

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212
<Product>dotnet-httpie</Product>
1313
<Authors>WeihanLi</Authors>
1414
<Copyright>Copyright 2021-$([System.DateTime]::Now.Year) (c) WeihanLi</Copyright>
15+
<NoWarn>NU1507;</NoWarn>
1516
</PropertyGroup>
1617
<ItemGroup>
1718
<Using Include="WeihanLi.Common"/>

Directory.Build.targets

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
<Project>
2+
</Project>

Directory.Packages.props

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
<Project>
2+
<PropertyGroup>
3+
<!-- Enable central package management -->
4+
<ManagePackageVersionsCentrally>true</ManagePackageVersionsCentrally>
5+
</PropertyGroup>
6+
<ItemGroup>
7+
<PackageVersion Include="JsonSchema.Net" Version="2.4.0" />
8+
<PackageVersion Include="MathNet.Numerics.Signed" Version="5.0.0" />
9+
<PackageVersion Include="Microsoft.Extensions.Logging.Console" Version="6.0.0" />
10+
<PackageVersion Include="System.CommandLine" Version="2.0.0-beta4.22272.1" />
11+
<PackageVersion Include="WeihanLi.Common" Version="1.0.52" />
12+
<PackageVersion Include="WeihanLi.Npoi" Version="2.2.0" />
13+
</ItemGroup>
14+
<ItemGroup>
15+
<PackageVersion Include="Microsoft.NET.Test.Sdk" Version="17.2.0" />
16+
<PackageVersion Include="FluentAssertions" Version="6.7.0" />
17+
<PackageVersion Include="Moq" Version="4.18.1" />
18+
<PackageVersion Include="xunit" Version="2.4.1" />
19+
<PackageVersion Include="Xunit.DependencyInjection" Version="8.5.0" />
20+
<PackageVersion Include="xunit.runner.visualstudio" Version="2.4.5" />
21+
<PackageVersion Include="coverlet.collector" Version="3.1.2" />
22+
</ItemGroup>
23+
</Project>

Dockerfile

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,8 @@ WORKDIR /app
77
COPY ./src/ ./src/
88
COPY ./build/ ./build/
99
COPY ./Directory.Build.props ./
10+
COPY ./Directory.Build.targets ./
11+
COPY ./Directory.Packages.props ./
1012
WORKDIR /app/src/HTTPie/
1113
RUN dotnet publish -c Release --self-contained --use-current-runtime -p:AssemblyName=http -p:PublishSingleFile=true -p:PublishTrimmed=true -p:EnableCompressionInSingleFile=true -o /app/artifacts
1214

build/version.props

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
11
<Project>
22
<PropertyGroup>
33
<VersionMajor>0</VersionMajor>
4-
<VersionMinor>4</VersionMinor>
5-
<VersionPatch>3</VersionPatch>
4+
<VersionMinor>5</VersionMinor>
5+
<VersionPatch>0</VersionPatch>
66
<VersionPrefix>$(VersionMajor).$(VersionMinor).$(VersionPatch)</VersionPrefix>
77
<InformationalVersion>$(PackageVersion)</InformationalVersion>
88
</PropertyGroup>

nuget.config

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
<?xml version="1.0" encoding="utf-8"?>
2+
<configuration>
3+
<packageSources>
4+
<!--To inherit the global NuGet package sources remove the <clear/> line below -->
5+
<clear />
6+
<add key="nuget" value="https://api.nuget.org/v3/index.json" />
7+
</packageSources>
8+
</configuration>

src/HTTPie/Abstractions/IHttpHandlerMiddleware.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,5 +5,5 @@ namespace HTTPie.Abstractions;
55

66
public interface IHttpHandlerMiddleware : IPlugin
77
{
8-
Task Invoke(HttpClientHandler httpClientHandler, Func<Task> next);
8+
Task Invoke(HttpClientHandler httpClientHandler, Func<HttpClientHandler, Task> next);
99
}

src/HTTPie/Abstractions/IPlugin.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,5 +5,5 @@ namespace HTTPie.Abstractions;
55

66
public interface IPlugin
77
{
8-
ICollection<Option> SupportedOptions() => Array.Empty<Option>();
8+
Option[] SupportedOptions() => Array.Empty<Option>();
99
}

src/HTTPie/Abstractions/IRequestMiddleware.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,5 +7,5 @@ namespace HTTPie.Abstractions;
77

88
public interface IRequestMiddleware : IPlugin
99
{
10-
Task Invoke(HttpRequestModel requestModel, Func<Task> next);
10+
Task Invoke(HttpRequestModel requestModel, Func<HttpRequestModel, Task> next);
1111
}

src/HTTPie/Abstractions/IResponseMiddleware.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,5 +7,5 @@ namespace HTTPie.Abstractions;
77

88
public interface IResponseMiddleware : IPlugin
99
{
10-
Task Invoke(HttpContext context, Func<Task> next);
10+
Task Invoke(HttpContext context, Func<HttpContext, Task> next);
1111
}

src/HTTPie/HTTPie.csproj

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -16,11 +16,11 @@
1616
<Using Include="System.CommandLine.Parsing" />
1717
</ItemGroup>
1818
<ItemGroup>
19-
<PackageReference Include="JsonSchema.Net" Version="2.3.0" />
20-
<PackageReference Include="MathNet.Numerics.Signed" Version="5.0.0" />
21-
<PackageReference Include="Microsoft.Extensions.Logging.Console" Version="6.0.0" />
22-
<PackageReference Include="System.CommandLine" Version="2.0.0-beta3.22114.1" />
23-
<PackageReference Include="WeihanLi.Common" Version="1.0.51" />
24-
<PackageReference Include="WeihanLi.Npoi" Version="2.0.2" />
19+
<PackageReference Include="JsonSchema.Net" />
20+
<PackageReference Include="MathNet.Numerics.Signed" />
21+
<PackageReference Include="Microsoft.Extensions.Logging.Console" />
22+
<PackageReference Include="System.CommandLine" />
23+
<PackageReference Include="WeihanLi.Common" />
24+
<PackageReference Include="WeihanLi.Npoi" />
2525
</ItemGroup>
2626
</Project>

src/HTTPie/Implement/CsvLoadTestExporter.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ static CsvLoadTestExporter()
1717

1818
private static readonly Option<string> OutputCsvPathOption = new("--export-csv-path", "Expected export csv file path");
1919

20-
public ICollection<Option> SupportedOptions()
20+
public Option[] SupportedOptions()
2121
{
2222
return new[] { OutputCsvPathOption };
2323
}

src/HTTPie/Implement/JsonLoadTestExporter.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ public sealed class JsonLoadTestExporter : ILoadTestExporter
1111
{
1212
private static readonly Option<string> OutputJsonPathOption = new("--export-json-path", "Expected export json file path");
1313

14-
public ICollection<Option> SupportedOptions()
14+
public Option[] SupportedOptions()
1515
{
1616
return new[] { OutputJsonPathOption };
1717
}

src/HTTPie/Implement/LoadTestExporterSelector.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ public sealed class LoadTestExporterSelector : ILoadTestExporterSelector
1212
private readonly Dictionary<string, ILoadTestExporter> _exporters;
1313
private static readonly Option<string> ExporterTypeOption = new("--exporter-type", "Load test result exporter type");
1414

15-
public ICollection<Option> SupportedOptions()
15+
public Option[] SupportedOptions()
1616
{
1717
return new[] { ExporterTypeOption };
1818
}

src/HTTPie/Implement/OutputFormatter.cs

Lines changed: 36 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -27,14 +27,26 @@ public sealed class OutputFormatter : IOutputFormatter
2727
{
2828
private readonly IServiceProvider _serviceProvider;
2929
private readonly ILogger<OutputFormatter> _logger;
30-
private static readonly Option<PrettyOptions> PrettyOption = new("--pretty", () => PrettyOptions.All, "pretty output");
3130

32-
private static readonly Option QuietOption = new(new[] { "--quiet", "-q" }, "quiet mode, output nothing");
33-
public static readonly Option OfflineOption = new("--offline", "offline mode, would not send the request, just print request info");
34-
private static readonly Option OutputHeadersOption = new(new[] { "-h", "--headers" }, "output response headers only");
35-
private static readonly Option OutputBodyOption = new(new[] { "-b", "--body" }, "output response headers and response body only");
36-
private static readonly Option OutputVerboseOption = new(new[] { "-v", "--verbose" }, "output request/response, response headers and response body");
37-
private static readonly Option<string> OutputPrintModeOption = new(new[] { "-p", "--print" }, "print mode, output specific info,H:request headers,B:request body,h:response headers,b:response body");
31+
private static readonly Option<PrettyOptions> PrettyOption = new("--pretty", () => PrettyOptions.All,
32+
"pretty output");
33+
34+
private static readonly Option<bool> QuietOption = new(new[] { "--quiet", "-q" }, "quiet mode, output nothing");
35+
36+
public static readonly Option<bool> OfflineOption =
37+
new("--offline", "offline mode, would not send the request, just print request info");
38+
39+
private static readonly Option<bool> OutputHeadersOption =
40+
new(new[] { "-h", "--headers" }, "output response headers only");
41+
42+
private static readonly Option<bool> OutputBodyOption =
43+
new(new[] { "-b", "--body" }, "output response headers and response body only");
44+
45+
private static readonly Option<bool> OutputVerboseOption = new(new[] { "-v", "--verbose" },
46+
"output request/response, response headers and response body");
47+
48+
private static readonly Option<string> OutputPrintModeOption = new(new[] { "-p", "--print" },
49+
"print mode, output specific info,H:request headers,B:request body,h:response headers,b:response body");
3850

3951

4052
public OutputFormatter(IServiceProvider serviceProvider, ILogger<OutputFormatter> logger)
@@ -43,24 +55,19 @@ public OutputFormatter(IServiceProvider serviceProvider, ILogger<OutputFormatter
4355
_logger = logger;
4456
}
4557

46-
public ICollection<Option> SupportedOptions() => new HashSet<Option>()
47-
{
48-
OfflineOption,
49-
QuietOption,
50-
OutputHeadersOption,
51-
OutputBodyOption,
52-
OutputVerboseOption,
53-
OutputPrintModeOption,
54-
55-
PrettyOption,
56-
};
58+
public Option[] SupportedOptions() => new Option[]
59+
{
60+
OfflineOption, QuietOption, OutputHeadersOption, OutputBodyOption, OutputVerboseOption,
61+
OutputPrintModeOption, PrettyOption,
62+
};
5763

5864
public static OutputFormat GetOutputFormat(HttpContext httpContext)
5965
{
6066
if (httpContext.TryGetProperty<OutputFormat>(Constants.ResponseOutputFormatPropertyName, out var outputFormat))
6167
{
6268
return outputFormat;
6369
}
70+
6471
outputFormat = OutputFormat.ResponseInfoWithTimestamp;
6572

6673
var requestModel = httpContext.Request;
@@ -89,16 +96,17 @@ public static OutputFormat GetOutputFormat(HttpContext httpContext)
8996
var mode = requestModel.ParseResult.GetValueForOption(OutputPrintModeOption);
9097
if (!string.IsNullOrEmpty(mode))
9198
outputFormat = mode.Select(m => m switch
92-
{
93-
'H' => OutputFormat.RequestHeaders,
94-
'B' => OutputFormat.RequestBody,
95-
'h' => OutputFormat.ResponseHeaders,
96-
'b' => OutputFormat.ResponseBody,
97-
't' => OutputFormat.Timestamp,
98-
_ => OutputFormat.None
99-
})
99+
{
100+
'H' => OutputFormat.RequestHeaders,
101+
'B' => OutputFormat.RequestBody,
102+
'h' => OutputFormat.ResponseHeaders,
103+
'b' => OutputFormat.ResponseBody,
104+
't' => OutputFormat.Timestamp,
105+
_ => OutputFormat.None
106+
})
100107
.Aggregate(OutputFormat.None, (current, format) => current | format);
101108
}
109+
102110
httpContext.SetProperty(Constants.ResponseOutputFormatPropertyName, outputFormat);
103111
return outputFormat;
104112
}
@@ -122,6 +130,7 @@ private static string GetCommonOutput(HttpContext httpContext, OutputFormat outp
122130
output.AppendLine(GetRequestVersionAndStatus(requestModel));
123131
output.AppendLine(GetHeadersString(requestModel.Headers));
124132
}
133+
125134
if (outputFormat.HasFlag(OutputFormat.RequestBody) && !string.IsNullOrEmpty(requestModel.Body))
126135
{
127136
output.AppendLineIf(string.Empty, output.Length > 0);
@@ -137,6 +146,7 @@ private static string GetCommonOutput(HttpContext httpContext, OutputFormat outp
137146
output.AppendLine(GetResponseVersionAndStatus(responseModel));
138147
output.AppendLine(GetHeadersString(responseModel.Headers));
139148
}
149+
140150
if (outputFormat.HasFlag(OutputFormat.ResponseBody) && !string.IsNullOrEmpty(responseModel.Body))
141151
{
142152
output.AppendLineIf(string.Empty, output.Length > requestLength);
@@ -242,4 +252,3 @@ private static string GetHeadersString(IDictionary<string, StringValues> headers
242252
$"{headers.Select(h => $"{h.Key}: {h.Value}").OrderBy(h => h).StringJoin(Environment.NewLine)}";
243253
}
244254
}
245-

src/HTTPie/Implement/RequestExecutor.cs

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -160,14 +160,18 @@ private async Task<HttpResponseModel> InvokeRequest(HttpClient httpClient, HttpC
160160
LogRequestMessage(requestMessage);
161161
httpContext.Request.Timestamp = DateTimeOffset.Now;
162162
var startTime = Stopwatch.GetTimestamp();
163-
using var responseMessage = await httpClient.SendAsync(requestMessage);
163+
using var responseMessage = await httpClient.SendAsync(requestMessage, httpContext.CancellationToken);
164164
var elapsed = ProfilerHelper.GetElapsedTime(startTime);
165165
LogResponseMessage(responseMessage);
166166
responseModel = await _responseMapper.ToResponseModel(responseMessage);
167167
responseModel.Elapsed = elapsed;
168168
responseModel.Timestamp = httpContext.Request.Timestamp.Add(elapsed);
169169
LogRequestDuration(httpContext.Request.Url, httpContext.Request.Method, responseModel.StatusCode, elapsed);
170170
}
171+
catch (OperationCanceledException operationCanceledException) when (httpContext.CancellationToken.IsCancellationRequested)
172+
{
173+
LogRequestCancelled(operationCanceledException);
174+
}
171175
catch (Exception exception)
172176
{
173177
LogException(exception);
@@ -192,4 +196,8 @@ private async Task<HttpResponseModel> InvokeRequest(HttpClient httpClient, HttpC
192196

193197
[LoggerMessage(Level = LogLevel.Error, EventId = 1001, Message = "Send httpRequest exception")]
194198
private partial void LogException(Exception exception);
199+
200+
201+
[LoggerMessage(Level = LogLevel.Warning, EventId = 1002, Message = "Request cancelled")]
202+
private partial void LogRequestCancelled(Exception exception);
195203
}

src/HTTPie/Middleware/AuthorizationMiddleware.cs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -22,9 +22,9 @@ static AuthorizationMiddleware()
2222
});
2323
}
2424

25-
public ICollection<Option> SupportedOptions() => new Option[] { AuthenticationTypeOption, AuthenticationValueOption };
25+
public Option[] SupportedOptions() => new Option[] { AuthenticationTypeOption, AuthenticationValueOption };
2626

27-
public Task Invoke(HttpRequestModel requestModel, Func<Task> next)
27+
public Task Invoke(HttpRequestModel requestModel, Func<HttpRequestModel, Task> next)
2828
{
2929
if (requestModel.ParseResult.HasOption(AuthenticationValueOption))
3030
{
@@ -36,7 +36,7 @@ public Task Invoke(HttpRequestModel requestModel, Func<Task> next)
3636
requestModel.Headers.TryAdd(Constants.AuthorizationHeaderName, authHeaderValue);
3737
}
3838
}
39-
return next();
39+
return next(requestModel);
4040
}
4141

4242
private static string GetAuthHeader(string? authType, string authValue)

src/HTTPie/Middleware/DefaultRequestMiddleware.cs

Lines changed: 6 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -17,18 +17,13 @@ public DefaultRequestMiddleware(ILogger logger)
1717
_logger = logger;
1818
}
1919

20-
private static readonly Option DebugOption = new("--debug", "Enable debug mode, output debug log");
20+
private static readonly Option<bool> DebugOption = new("--debug", "Enable debug mode, output debug log");
2121
private static readonly Option<string> SchemaOption = new("--schema", "The HTTP request schema");
2222
private static readonly Option<Version> HttpVersionOption = new("--httpVersion", "The HTTP request HTTP version");
2323

24-
public ICollection<Option> SupportedOptions() => new HashSet<Option>()
25-
{
26-
DebugOption,
27-
SchemaOption,
28-
HttpVersionOption,
29-
};
24+
public Option[] SupportedOptions() => new Option[] { DebugOption, SchemaOption, HttpVersionOption, };
3025

31-
public async Task Invoke(HttpRequestModel requestModel, Func<Task> next)
26+
public Task Invoke(HttpRequestModel requestModel, Func<HttpRequestModel, Task> next)
3227
{
3328
var schema = requestModel.ParseResult.GetValueForOption(SchemaOption);
3429
if (!string.IsNullOrEmpty(schema)) requestModel.Schema = schema;
@@ -42,6 +37,7 @@ public async Task Invoke(HttpRequestModel requestModel, Func<Task> next)
4237
if (requestModel.Url.StartsWith(":/")) requestModel.Url = $"localhost{requestModel.Url[1..]}";
4338
if (requestModel.Url.StartsWith(':')) requestModel.Url = $"localhost{requestModel.Url}";
4439
}
40+
4541
if (requestModel.Url.IndexOf("://", StringComparison.Ordinal) < 0)
4642
requestModel.Url = $"{requestModel.Schema}://{requestModel.Url}";
4743
if (requestModel.Url.StartsWith("://", StringComparison.Ordinal))
@@ -66,6 +62,7 @@ public async Task Invoke(HttpRequestModel requestModel, Func<Task> next)
6662
}
6763

6864
requestModel.Headers.TryAdd("User-Agent", Constants.DefaultUserAgent);
69-
await next();
65+
66+
return next(requestModel);
7067
}
7168
}

src/HTTPie/Middleware/DefaultResponseMiddleware.cs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ namespace HTTPie.Middleware;
1010

1111
public sealed class DefaultResponseMiddleware : IResponseMiddleware
1212
{
13-
public Task Invoke(HttpContext context, Func<Task> next)
13+
public Task Invoke(HttpContext context, Func<HttpContext, Task> next)
1414
{
1515
var outputFormat = OutputFormatter.GetOutputFormat(context);
1616
if ((outputFormat & OutputFormat.Timestamp) != 0)
@@ -22,6 +22,6 @@ public Task Invoke(HttpContext context, Func<Task> next)
2222
context.Response.Headers.TryAdd(Constants.RequestDurationHeaderName, $"{context.Response.Elapsed.TotalMilliseconds}ms");
2323
}
2424
}
25-
return next();
25+
return next(context);
2626
}
2727
}

0 commit comments

Comments
 (0)