Skip to content

Commit 3a1f60b

Browse files
committed
[增加] Http 模块新增 HttpResponse、HttpResponseEncoder、HttpKeepAliveFilter、ServerSentEventWriter、HttpExtensions 等 HTTP 服务功能
1 parent c474489 commit 3a1f60b

9 files changed

Lines changed: 749 additions & 723 deletions

File tree

Lines changed: 102 additions & 108 deletions
Original file line numberDiff line numberDiff line change
@@ -1,123 +1,117 @@
1-
using System;
2-
using System.Threading;
3-
using System.Threading.Tasks;
4-
using GameFrameX.SuperSocket.Http;
51
using GameFrameX.SuperSocket.Server.Abstractions.Session;
6-
using SuperSocket.Connection;
72

8-
namespace SuperSocket.Http
3+
namespace GameFrameX.SuperSocket.Http;
4+
5+
/// <summary>
6+
/// Extension methods for easier HTTP functionality usage.
7+
/// </summary>
8+
public static class HttpExtensions
99
{
1010
/// <summary>
11-
/// Extension methods for easier HTTP functionality usage.
11+
/// Sends an HTTP response to the session.
1212
/// </summary>
13-
public static class HttpExtensions
13+
/// <param name="session">The session to send the response to.</param>
14+
/// <param name="response">The HTTP response to send.</param>
15+
/// <param name="cancellationToken">A token to monitor for cancellation requests.</param>
16+
/// <returns>A task that represents the asynchronous operation.</returns>
17+
public static async ValueTask SendHttpResponseAsync(
18+
this IAppSession session,
19+
HttpResponse response,
20+
CancellationToken cancellationToken = default)
1421
{
15-
/// <summary>
16-
/// Sends an HTTP response to the session.
17-
/// </summary>
18-
/// <param name="session">The session to send the response to.</param>
19-
/// <param name="response">The HTTP response to send.</param>
20-
/// <param name="cancellationToken">A token to monitor for cancellation requests.</param>
21-
/// <returns>A task that represents the asynchronous operation.</returns>
22-
public static async ValueTask SendHttpResponseAsync(
23-
this IAppSession session,
24-
HttpResponse response,
25-
CancellationToken cancellationToken = default)
26-
{
27-
await session.SendAsync(HttpResponseEncoder.Instance, response, cancellationToken);
28-
}
22+
await session.SendAsync(HttpResponseEncoder.Instance, response, cancellationToken);
23+
}
2924

30-
/// <summary>
31-
/// Sends a simple HTTP response with the specified status and body.
32-
/// </summary>
33-
/// <param name="session">The session to send the response to.</param>
34-
/// <param name="statusCode">The HTTP status code.</param>
35-
/// <param name="body">The response body.</param>
36-
/// <param name="contentType">The content type. Defaults to "text/plain".</param>
37-
/// <param name="keepAlive">Whether to keep the connection alive.</param>
38-
/// <param name="cancellationToken">A token to monitor for cancellation requests.</param>
39-
/// <returns>A task that represents the asynchronous operation.</returns>
40-
public static async ValueTask SendHttpResponseAsync(
41-
this IAppSession session,
42-
int statusCode,
43-
string body = "",
44-
string contentType = "text/plain",
45-
bool keepAlive = true,
46-
CancellationToken cancellationToken = default)
47-
{
48-
var response = new HttpResponse(statusCode);
49-
response.SetContentType(contentType);
50-
response.Body = body;
51-
response.KeepAlive = keepAlive;
25+
/// <summary>
26+
/// Sends a simple HTTP response with the specified status and body.
27+
/// </summary>
28+
/// <param name="session">The session to send the response to.</param>
29+
/// <param name="statusCode">The HTTP status code.</param>
30+
/// <param name="body">The response body.</param>
31+
/// <param name="contentType">The content type. Defaults to "text/plain".</param>
32+
/// <param name="keepAlive">Whether to keep the connection alive.</param>
33+
/// <param name="cancellationToken">A token to monitor for cancellation requests.</param>
34+
/// <returns>A task that represents the asynchronous operation.</returns>
35+
public static async ValueTask SendHttpResponseAsync(
36+
this IAppSession session,
37+
int statusCode,
38+
string body = "",
39+
string contentType = "text/plain",
40+
bool keepAlive = true,
41+
CancellationToken cancellationToken = default)
42+
{
43+
var response = new HttpResponse(statusCode);
44+
response.SetContentType(contentType);
45+
response.Body = body;
46+
response.KeepAlive = keepAlive;
5247

53-
await session.SendHttpResponseAsync(response, cancellationToken);
54-
}
48+
await session.SendHttpResponseAsync(response, cancellationToken);
49+
}
5550

56-
/// <summary>
57-
/// Sends a JSON HTTP response.
58-
/// </summary>
59-
/// <param name="session">The session to send the response to.</param>
60-
/// <param name="jsonData">The JSON data to send.</param>
61-
/// <param name="statusCode">The HTTP status code. Defaults to 200.</param>
62-
/// <param name="keepAlive">Whether to keep the connection alive.</param>
63-
/// <param name="cancellationToken">A token to monitor for cancellation requests.</param>
64-
/// <returns>A task that represents the asynchronous operation.</returns>
65-
public static async ValueTask SendJsonResponseAsync(
66-
this IAppSession session,
67-
string jsonData,
68-
int statusCode = 200,
69-
bool keepAlive = true,
70-
CancellationToken cancellationToken = default)
71-
{
72-
await session.SendHttpResponseAsync(statusCode, jsonData, "application/json", keepAlive, cancellationToken);
73-
}
51+
/// <summary>
52+
/// Sends a JSON HTTP response.
53+
/// </summary>
54+
/// <param name="session">The session to send the response to.</param>
55+
/// <param name="jsonData">The JSON data to send.</param>
56+
/// <param name="statusCode">The HTTP status code. Defaults to 200.</param>
57+
/// <param name="keepAlive">Whether to keep the connection alive.</param>
58+
/// <param name="cancellationToken">A token to monitor for cancellation requests.</param>
59+
/// <returns>A task that represents the asynchronous operation.</returns>
60+
public static async ValueTask SendJsonResponseAsync(
61+
this IAppSession session,
62+
string jsonData,
63+
int statusCode = 200,
64+
bool keepAlive = true,
65+
CancellationToken cancellationToken = default)
66+
{
67+
await session.SendHttpResponseAsync(statusCode, jsonData, "application/json", keepAlive, cancellationToken);
68+
}
7469

75-
/// <summary>
76-
/// Creates a Server-Sent Events writer for the session.
77-
/// </summary>
78-
/// <param name="session">The session to create the SSE writer for.</param>
79-
/// <param name="options">Optional SSE configuration options.</param>
80-
/// <returns>A new ServerSentEventWriter instance.</returns>
81-
public static ServerSentEventWriter CreateSSEWriter(this IAppSession session, ServerSentEventsOptions options = null)
82-
{
83-
return new ServerSentEventWriter(session.Connection, options);
84-
}
70+
/// <summary>
71+
/// Creates a Server-Sent Events writer for the session.
72+
/// </summary>
73+
/// <param name="session">The session to create the SSE writer for.</param>
74+
/// <param name="options">Optional SSE configuration options.</param>
75+
/// <returns>A new ServerSentEventWriter instance.</returns>
76+
public static ServerSentEventWriter CreateSSEWriter(this IAppSession session, ServerSentEventsOptions options = null)
77+
{
78+
return new ServerSentEventWriter(session.Connection, options);
79+
}
8580

86-
/// <summary>
87-
/// Starts a Server-Sent Events stream for the session.
88-
/// </summary>
89-
/// <param name="session">The session to start SSE for.</param>
90-
/// <param name="options">Optional SSE configuration options.</param>
91-
/// <param name="cancellationToken">A token to monitor for cancellation requests.</param>
92-
/// <returns>A new ServerSentEventWriter instance that has already sent the initial response.</returns>
93-
public static async ValueTask<ServerSentEventWriter> StartSSEAsync(
94-
this IAppSession session,
95-
ServerSentEventsOptions options = null,
96-
CancellationToken cancellationToken = default)
97-
{
98-
var writer = session.CreateSSEWriter(options);
99-
await writer.SendInitialResponseAsync(cancellationToken);
100-
return writer;
101-
}
81+
/// <summary>
82+
/// Starts a Server-Sent Events stream for the session.
83+
/// </summary>
84+
/// <param name="session">The session to start SSE for.</param>
85+
/// <param name="options">Optional SSE configuration options.</param>
86+
/// <param name="cancellationToken">A token to monitor for cancellation requests.</param>
87+
/// <returns>A new ServerSentEventWriter instance that has already sent the initial response.</returns>
88+
public static async ValueTask<ServerSentEventWriter> StartSSEAsync(
89+
this IAppSession session,
90+
ServerSentEventsOptions options = null,
91+
CancellationToken cancellationToken = default)
92+
{
93+
var writer = session.CreateSSEWriter(options);
94+
await writer.SendInitialResponseAsync(cancellationToken);
95+
return writer;
96+
}
10297

103-
/// <summary>
104-
/// Checks if the HTTP request accepts Server-Sent Events.
105-
/// </summary>
106-
/// <param name="request">The HTTP request to check.</param>
107-
/// <returns>True if the request accepts SSE, false otherwise.</returns>
108-
public static bool IsSSERequest(this HttpRequest request)
109-
{
110-
return request.AcceptsEventStream;
111-
}
98+
/// <summary>
99+
/// Checks if the HTTP request accepts Server-Sent Events.
100+
/// </summary>
101+
/// <param name="request">The HTTP request to check.</param>
102+
/// <returns>True if the request accepts SSE, false otherwise.</returns>
103+
public static bool IsSSERequest(this HttpRequest request)
104+
{
105+
return request.AcceptsEventStream;
106+
}
112107

113-
/// <summary>
114-
/// Checks if the HTTP request wants to keep the connection alive.
115-
/// </summary>
116-
/// <param name="request">The HTTP request to check.</param>
117-
/// <returns>True if keep-alive is requested, false otherwise.</returns>
118-
public static bool IsKeepAliveRequest(this HttpRequest request)
119-
{
120-
return request.KeepAlive;
121-
}
108+
/// <summary>
109+
/// Checks if the HTTP request wants to keep the connection alive.
110+
/// </summary>
111+
/// <param name="request">The HTTP request to check.</param>
112+
/// <returns>True if keep-alive is requested, false otherwise.</returns>
113+
public static bool IsKeepAliveRequest(this HttpRequest request)
114+
{
115+
return request.KeepAlive;
122116
}
123117
}
Lines changed: 73 additions & 75 deletions
Original file line numberDiff line numberDiff line change
@@ -1,97 +1,95 @@
1-
using System;
21
using System.Buffers;
3-
using GameFrameX.SuperSocket.Http;
42
using GameFrameX.SuperSocket.ProtoBase;
5-
using SuperSocket.ProtoBase;
63

7-
namespace SuperSocket.Http
4+
namespace GameFrameX.SuperSocket.Http;
5+
6+
/// <summary>
7+
/// Represents a pipeline filter for parsing HTTP requests with keep-alive support.
8+
/// This filter can handle multiple requests over a single connection.
9+
/// </summary>
10+
public class HttpKeepAliveFilter : IPipelineFilter<HttpRequest>
811
{
12+
private readonly HttpPipelineFilter _innerFilter;
13+
private bool _connectionClosed;
14+
915
/// <summary>
10-
/// Represents a pipeline filter for parsing HTTP requests with keep-alive support.
11-
/// This filter can handle multiple requests over a single connection.
16+
/// Initializes a new instance of the <see cref="HttpKeepAliveFilter" /> class.
1217
/// </summary>
13-
public class HttpKeepAliveFilter : IPipelineFilter<HttpRequest>
18+
public HttpKeepAliveFilter()
1419
{
15-
private readonly HttpPipelineFilter _innerFilter;
16-
private bool _connectionClosed = false;
20+
_innerFilter = new HttpPipelineFilter();
21+
}
1722

18-
/// <summary>
19-
/// Initializes a new instance of the <see cref="HttpKeepAliveFilter"/> class.
20-
/// </summary>
21-
public HttpKeepAliveFilter()
22-
{
23-
_innerFilter = new HttpPipelineFilter();
24-
}
23+
/// <summary>
24+
/// Gets or sets the package decoder for the HTTP request.
25+
/// </summary>
26+
public IPackageDecoder<HttpRequest> Decoder
27+
{
28+
get { return _innerFilter.Decoder; }
29+
set { _innerFilter.Decoder = value; }
30+
}
2531

26-
/// <summary>
27-
/// Gets or sets the package decoder for the HTTP request.
28-
/// </summary>
29-
public IPackageDecoder<HttpRequest> Decoder
30-
{
31-
get => _innerFilter.Decoder;
32-
set => _innerFilter.Decoder = value;
33-
}
32+
/// <summary>
33+
/// Gets or sets the next pipeline filter in the chain.
34+
/// </summary>
35+
public IPipelineFilter<HttpRequest> NextFilter
36+
{
37+
get { return _connectionClosed ? null : this; }
38+
set { } // Keep-alive filter manages its own chain
39+
}
3440

35-
/// <summary>
36-
/// Gets or sets the next pipeline filter in the chain.
37-
/// </summary>
38-
public IPipelineFilter<HttpRequest> NextFilter
39-
{
40-
get => _connectionClosed ? null : this;
41-
set { } // Keep-alive filter manages its own chain
42-
}
41+
/// <summary>
42+
/// Gets or sets the context associated with the pipeline filter.
43+
/// </summary>
44+
public object Context
45+
{
46+
get { return _innerFilter.Context; }
47+
set { _innerFilter.Context = value; }
48+
}
4349

44-
/// <summary>
45-
/// Gets or sets the context associated with the pipeline filter.
46-
/// </summary>
47-
public object Context
48-
{
49-
get => _innerFilter.Context;
50-
set => _innerFilter.Context = value;
50+
/// <summary>
51+
/// Filters the data stream to parse an HTTP request with keep-alive support.
52+
/// </summary>
53+
/// <param name="reader">The sequence reader for the data stream.</param>
54+
/// <returns>The parsed <see cref="HttpRequest" />, or <c>null</c> if more data is needed.</returns>
55+
public HttpRequest Filter(ref SequenceReader<byte> reader)
56+
{
57+
if (_connectionClosed)
58+
{
59+
return null;
5160
}
5261

53-
/// <summary>
54-
/// Filters the data stream to parse an HTTP request with keep-alive support.
55-
/// </summary>
56-
/// <param name="reader">The sequence reader for the data stream.</param>
57-
/// <returns>The parsed <see cref="HttpRequest"/>, or <c>null</c> if more data is needed.</returns>
58-
public HttpRequest Filter(ref SequenceReader<byte> reader)
62+
var request = _innerFilter.Filter(ref reader);
63+
64+
if (request != null)
5965
{
60-
if (_connectionClosed)
61-
return null;
66+
// Reset the inner filter for the next request
67+
_innerFilter.Reset();
6268

63-
var request = _innerFilter.Filter(ref reader);
64-
65-
if (request != null)
69+
// Check if this request should close the connection
70+
if (!request.KeepAlive)
6671
{
67-
// Reset the inner filter for the next request
68-
_innerFilter.Reset();
69-
70-
// Check if this request should close the connection
71-
if (!request.KeepAlive)
72-
{
73-
_connectionClosed = true;
74-
}
72+
_connectionClosed = true;
7573
}
76-
77-
return request;
7874
}
7975

80-
/// <summary>
81-
/// Resets the state of the pipeline filter.
82-
/// </summary>
83-
public void Reset()
84-
{
85-
_innerFilter.Reset();
86-
_connectionClosed = false;
87-
}
76+
return request;
77+
}
8878

89-
/// <summary>
90-
/// Marks the connection as closed, preventing further request processing.
91-
/// </summary>
92-
public void CloseConnection()
93-
{
94-
_connectionClosed = true;
95-
}
79+
/// <summary>
80+
/// Resets the state of the pipeline filter.
81+
/// </summary>
82+
public void Reset()
83+
{
84+
_innerFilter.Reset();
85+
_connectionClosed = false;
86+
}
87+
88+
/// <summary>
89+
/// Marks the connection as closed, preventing further request processing.
90+
/// </summary>
91+
public void CloseConnection()
92+
{
93+
_connectionClosed = true;
9694
}
9795
}

0 commit comments

Comments
 (0)